<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<meta name="theme-color" content="#222"><meta name="generator" content="Hexo 7.3.0">

  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32.ico">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16.ico">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">



<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" integrity="sha256-wiz7ZSCn/btzhjKDQBms9Hx4sSeUYsDrTLg7roPstac=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.1.1/animate.min.css" integrity="sha256-PR7ttpcvz8qrF57fur/yAx1qXMFJeJFiA6pSzWi0OIE=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fancyapps-ui/5.0.28/fancybox/fancybox.css" integrity="sha256-6cQIC71/iBIYXFK+0RHAvwmjwWzkWd+r7v/BX3/vZDc=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/pace/1.2.4/themes/green/pace-theme-minimal.css">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/pace/1.2.4/pace.min.js" integrity="sha256-gqd7YTjg/BtfqWSwsJOvndl0Bxc8gFImLEkXQT8+qj0=" crossorigin="anonymous"></script>

<script class="next-config" data-name="main" type="application/json">{"hostname":"sumumm.github.io","root":"/","images":"/images","scheme":"Gemini","darkmode":false,"version":"8.19.2","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12},"copycode":{"enable":true,"style":"mac"},"fold":{"enable":true,"height":300},"bookmark":{"enable":false,"color":"#222","save":"auto"},"mediumzoom":false,"lazyload":true,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"stickytabs":false,"motion":{"enable":true,"async":true,"transition":{"menu_item":"fadeInDown","post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"i18n":{"placeholder":"搜索...","empty":"没有找到任何搜索结果：${query}","hits_time":"找到 ${hits} 个搜索结果（用时 ${time} 毫秒）","hits":"找到 ${hits} 个搜索结果"},"path":"/search.xml","localsearch":{"enable":true,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false}}</script><script src="/js/config.js"></script>

    <meta name="description" content="本文主要是kernel——编译单个内核模块的流程的相关笔记，若笔记中有错误或者不合适的地方，欢迎批评指正😃。">
<meta property="og:type" content="article">
<meta property="og:title" content="LV05-03-Kernel-03-02-make-single-module">
<meta property="og:url" content="https://sumumm.github.io/post/5d81934f.html">
<meta property="og:site_name" content="苏木">
<meta property="og:description" content="本文主要是kernel——编译单个内核模块的流程的相关笔记，若笔记中有错误或者不合适的地方，欢迎批评指正😃。">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV05-%E7%B3%BB%E7%BB%9F%E9%95%9C%E5%83%8F/LV05-03-Kernel-03-02-make-single-module/img/image-20241129000124387.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV05-%E7%B3%BB%E7%BB%9F%E9%95%9C%E5%83%8F/LV05-03-Kernel-03-02-make-single-module/img/image-20241129001133528.png">
<meta property="article:published_time" content="2024-11-29T02:27:21.000Z">
<meta property="article:modified_time" content="2025-06-13T16:25:57.045Z">
<meta property="article:author" content="苏木">
<meta property="article:tag" content="LV05-系统镜像">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV05-%E7%B3%BB%E7%BB%9F%E9%95%9C%E5%83%8F/LV05-03-Kernel-03-02-make-single-module/img/image-20241129000124387.png">


<link rel="canonical" href="https://sumumm.github.io/post/5d81934f.html">



<script class="next-config" data-name="page" type="application/json">{"sidebar":"","isHome":false,"isPost":true,"lang":"zh-CN","comments":"","permalink":"https://sumumm.github.io/post/5d81934f.html","path":"post/5d81934f.html","title":"LV05-03-Kernel-03-02-make-single-module"}</script>

<script class="next-config" data-name="calendar" type="application/json">""</script>
<title>LV05-03-Kernel-03-02-make-single-module | 苏木</title>
  








    <script src="/js/browser_tools_disable.js"></script>

  <noscript>
    <link rel="stylesheet" href="/css/noscript.css">
  </noscript>
<!-- hexo injector head_end start --><link rel="stylesheet" href="https://unpkg.com/hexo-next-tags-plus@latest/lib/tag_plus.css" media="defer" onload="this.media='all'"><!-- hexo injector head_end end --></head>

<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">
  <div class="headband"></div>

  <main class="main">
    <div class="column">
      <header class="header" itemscope itemtype="http://schema.org/WPHeader"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏" role="button">
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <i class="logo-line"></i>
      <p class="site-title">苏木</p>
      <i class="logo-line"></i>
    </a>
      <p class="site-subtitle" itemprop="description">我的学习之路</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger" aria-label="搜索" role="button">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>



<nav class="site-nav">
  <ul class="main-menu menu"><li class="menu-item menu-item-home"><a href="/" rel="section"><i class="fa fa-home fa-fw"></i>苏木的家</a></li><li class="menu-item menu-item-categories"><a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类页<span class="badge">42</span></a></li><li class="menu-item menu-item-archives"><a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档页<span class="badge">673</span></a></li><li class="menu-item menu-item-flink"><a href="/flink/" rel="section"><i class="fa fa-link fa-fw"></i>友人帐</a></li><li class="menu-item menu-item-about"><a href="/about/" rel="section"><i class="fa fa-user fa-fw"></i>关于我</a></li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup"><div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off" maxlength="80"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close" role="button">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div class="search-result-container no-result">
  <div class="search-result-icon">
    <i class="fa fa-spinner fa-pulse fa-5x"></i>
  </div>
</div>

    </div>
  </div>

</header>
        
  
  <aside class="sidebar">

    <div class="sidebar-inner sidebar-nav-active sidebar-toc-active">
      <ul class="sidebar-nav">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <div class="sidebar-panel-container">
        <!--noindex-->
        <div class="post-toc-wrap sidebar-panel">
            <div class="post-toc animated"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%B8%80%E3%80%81%E6%A6%82%E8%BF%B0"><span class="nav-text">一、概述</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-%E5%B8%AE%E5%8A%A9%E4%BF%A1%E6%81%AF"><span class="nav-text">1. 帮助信息</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-%E6%A8%A1%E5%9D%97%E7%BC%96%E8%AF%91%E5%91%BD%E4%BB%A4"><span class="nav-text">2. 模块编译命令</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%BA%8C%E3%80%81%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">二、函数说明</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-cmd%E5%87%BD%E6%95%B0"><span class="nav-text">1. cmd函数</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-1-echo-cmd"><span class="nav-text">1.1 $(echo-cmd)</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#1-1-1-escsq"><span class="nav-text">1.1.1 escsq</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#1-1-2-echo-why"><span class="nav-text">1.1.2 echo-why</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#1-1-3-%E6%80%BB%E7%BB%93"><span class="nav-text">1.1.3 总结</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-2-cmd-1"><span class="nav-text">1.2 $(cmd_$(1))</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-3-cmd%E5%88%B0%E5%BA%95%E5%9C%A8%E5%81%9A%E4%BB%80%E4%B9%88%EF%BC%9F"><span class="nav-text">1.3 cmd到底在做什么？</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-wanring%E5%87%BD%E6%95%B0"><span class="nav-text">2. wanring函数</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%B8%89%E3%80%81make-dir-file-ko"><span class="nav-text">三、make dir&#x2F;file.ko</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-ko%E7%9B%AE%E6%A0%87"><span class="nav-text">1. %.ko目标</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-1-cmd-crmodverdir"><span class="nav-text">1.1 cmd_crmodverdir</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-2-KBUILD-MODULES"><span class="nav-text">1.2 KBUILD_MODULES</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-3-build%E3%80%81build-dir"><span class="nav-text">1.3 build、build-dir</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#1-3-1-build"><span class="nav-text">1.3.1 build</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#1-3-2-build-dir"><span class="nav-text">1.3.2 build-dir</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#1-3-3-ko-o"><span class="nav-text">1.3.3 $(@:.ko&#x3D;.o)</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#1-3-4-%E5%91%BD%E4%BB%A4%E5%B1%95%E5%BC%80"><span class="nav-text">1.3.4 命令展开</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-4-ko%E8%A7%84%E5%88%99%E5%B1%95%E5%BC%80"><span class="nav-text">1.4 %.ko规则展开</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-Makefile-build"><span class="nav-text">2. Makefile.build </span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#2-1-obj%E4%B8%8Esrc"><span class="nav-text">2.1 obj与src</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-2-obj-o%E7%9B%AE%E6%A0%87"><span class="nav-text">2.2 $(obj)&#x2F;%.o目标</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#2-2-1-%E5%8C%B9%E9%85%8D%E5%93%AA%E4%B8%80%E4%B8%AA%E7%9B%AE%E6%A0%87%EF%BC%9F"><span class="nav-text">2.2.1 匹配哪一个目标？</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-2-2-call-cmd-force-checksrc"><span class="nav-text">2.2.2 $(call cmd,force_checksrc)</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-2-3-call-if-changed-rule-cc-o-c"><span class="nav-text">2.2.3 $(call if_changed_rule,cc_o_c)</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#2-2-3-1-any-prereq"><span class="nav-text">2.2.3.1 any-prereq</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#2-2-3-2-arg-check"><span class="nav-text">2.2.3.2 arg-check</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#2-2-3-3-rule-1"><span class="nav-text">2.2.3.3 $(rule_$(1))</span></a></li></ol></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3-rule-cc-o-c%E5%87%BD%E6%95%B0"><span class="nav-text">3. rule_cc_o_c函数</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#3-1-checksrc"><span class="nav-text">3.1 checksrc</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#3-1-1-cmd-checksrc"><span class="nav-text">3.1.1 $(cmd_checksrc)</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-1-2-call-echo-cmd-checksrc"><span class="nav-text">3.1.2 $(call echo-cmd,checksrc)</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-1-3-%E6%80%BB%E7%BB%93"><span class="nav-text">3.1.3 总结</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-2-call-cmd-and-fixdep-cc-o-c"><span class="nav-text">3.2 $(call cmd_and_fixdep,cc_o_c)</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#3-2-1-echo-cmd"><span class="nav-text">3.2.1 $(echo-cmd)</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-2-2-cmd-cc-o-c"><span class="nav-text">3.2.2 $(cmd_cc_o_c)</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-2-3-echo-cmd-cmd-1-%E5%81%9A%E4%BA%86%E4%BB%80%E4%B9%88%EF%BC%9F"><span class="nav-text">3.2.3 $(echo-cmd) $(cmd_$(1))做了什么？</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-3-cmd-checkdoc"><span class="nav-text">3.3 $(cmd_checkdoc)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-4-objtool"><span class="nav-text">3.4 objtool</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#3-4-1-cmd-objtool"><span class="nav-text">3.4.1 $(cmd_objtool)</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-4-2-call-echo-cmd-objtool"><span class="nav-text">3.4.2 $(call echo-cmd,objtool)</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-4-3-%E6%80%BB%E7%BB%93"><span class="nav-text">3.4.3 总结</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-5-cmd-modversions-c"><span class="nav-text">3.5 $(cmd_modversions_c)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-6-record-mcount"><span class="nav-text">3.6 record_mcount</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#3-6-1-cmd-record-mcount"><span class="nav-text">3.6.1 $(cmd_record_mcount)</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-6-2-call-echo-cmd-record-mcount"><span class="nav-text">3.6.2 $(call echo-cmd,record_mcount)</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-6-3-%E6%80%BB%E7%BB%93"><span class="nav-text">3.6.3 总结</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-7-rule-cc-o-c%E6%80%BB%E7%BB%93"><span class="nav-text">3.7 rule_cc_o_c总结</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#4-Makefile-modpost"><span class="nav-text">4. Makefile.modpost</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#4-1-%E6%96%87%E4%BB%B6%E7%BB%93%E6%9E%84"><span class="nav-text">4.1 文件结构</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#4-1-1-Step-1"><span class="nav-text">4.1.1 Step 1</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#4-1-2-Step-2-3-4"><span class="nav-text">4.1.2 Step 2&#x2F;3&#x2F;4</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#4-1-3-Step-5"><span class="nav-text">4.1.3 Step 5</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#4-1-4-%E6%89%80%E6%9C%89%E5%87%BA%E7%8E%B0%E7%9A%84%E7%9B%AE%E6%A0%87"><span class="nav-text">4.1.4 所有出现的目标</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-2-modpost%E7%9B%AE%E6%A0%87"><span class="nav-text">4.2 _modpost目标</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-3-modpost%E7%9B%AE%E6%A0%87"><span class="nav-text">4.3 __modpost目标</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#4-3-1-call-cmd-modpost"><span class="nav-text">4.3.1 $(call cmd,modpost)</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#4-3-2-wildcard-vmlinux"><span class="nav-text">4.3.2 $(wildcard vmlinux)</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#4-3-3-modules-ko-o"><span class="nav-text">4.3.3 $(modules:.ko&#x3D;.o)</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#4-3-4-%E6%80%BB%E7%BB%93"><span class="nav-text">4.3.4 总结</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-4-modpost%E7%9B%AE%E6%A0%87"><span class="nav-text">4.4 _modpost目标</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-5-modules-%E7%9B%AE%E6%A0%87"><span class="nav-text">4.5 $(modules)目标</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#4-5-1-if-changed%E5%87%BD%E6%95%B0"><span class="nav-text">4.5.1 if_changed函数</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#4-5-2-cmd-ld-ko-o"><span class="nav-text">4.5.2 cmd_ld_ko_o</span></a></li></ol></li></ol></li></ol></li></ol></div>
        </div>
        <!--/noindex-->

        <div class="site-overview-wrap sidebar-panel">
          <div class="site-author animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="苏木"
      src="/images/avatar.jpg">
  <p class="site-author-name" itemprop="name">苏木</p>
  <div class="site-description" itemprop="description">莫道桑榆晚，为霞尚满天</div>
</div>
<div class="site-state-wrap animated">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
        <a href="/archives/">
          <span class="site-state-item-count">673</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
          <a href="/categories/">
        <span class="site-state-item-count">42</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
        <span class="site-state-item-count">43</span>
        <span class="site-state-item-name">标签</span>
      </div>
  </nav>
</div>
  <div class="links-of-author animated">
      <span class="links-of-author-item">
        <a href="https://github.com/sumumm" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;sumumm" rel="noopener me" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a>
      </span>
  </div>

        </div>
      </div>
    </div>

    
  </aside>


    </div>

    <div class="main-inner post posts-expand">


  


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://sumumm.github.io/post/5d81934f.html">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.jpg">
      <meta itemprop="name" content="苏木">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="苏木">
      <meta itemprop="description" content="莫道桑榆晚，为霞尚满天">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="LV05-03-Kernel-03-02-make-single-module | 苏木">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          LV05-03-Kernel-03-02-make-single-module
        </h1>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2024-11-29 10:27:21" itemprop="dateCreated datePublished" datetime="2024-11-29T10:27:21+08:00">2024-11-29</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/" itemprop="url" rel="index"><span itemprop="name">嵌入式开发</span></a>
        </span>
          ，
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/" itemprop="url" rel="index"><span itemprop="name">02IMX6ULL平台</span></a>
        </span>
          ，
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV05-%E7%B3%BB%E7%BB%9F%E9%95%9C%E5%83%8F/" itemprop="url" rel="index"><span itemprop="name">LV05-系统镜像</span></a>
        </span>
    </span>

  
    <span class="post-meta-break"></span>
    <span class="post-meta-item" title="本文字数">
      <span class="post-meta-item-icon">
        <i class="far fa-file-word"></i>
      </span>
      <span class="post-meta-item-text">本文字数：</span>
      <span>11k</span>
    </span>
    <span class="post-meta-item" title="阅读时长">
      <span class="post-meta-item-icon">
        <i class="far fa-clock"></i>
      </span>
      <span class="post-meta-item-text">阅读时长 &asymp;</span>
      <span>41 分钟</span>
    </span>
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody"><p>本文主要是kernel——编译单个内核模块的流程的相关笔记，若笔记中有错误或者不合适的地方，欢迎批评指正😃。</p>
<span id="more"></span>

<!-- Photo: https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV05-%E7%B3%BB%E7%BB%9F%E9%95%9C%E5%83%8F/LV05-03-Kernel-03-02-make-single-module/img/ -->

<details class="folding-tag" blue><summary> 点击查看使用工具及版本 </summary>
              <div class='content'>
              <table>    <tr>        <td align="center" rowspan="5">PC端开发环境</td>        <td align="center" width=150px>Windows</td>        <td align="left">Windows11</td>    </tr>    <tr>        <td align="center">Ubuntu</td>        <td align="left">Ubuntu20.04.2的64位版本</td>      </tr>    <tr>        <td align="center">VMware® Workstation 17 Pro</td>        <td align="left">17.6.0 build-24238078</td>      </tr>    <tr>        <td align="center">终端软件</td>        <td align="left">MobaXterm(Professional Edition v23.0 Build 5042 (license))</td>    </tr>    <tr>        <td align="center">Win32DiskImager</td>        <td align="left">Win32DiskImager v1.0</td>      </tr>    <tr>        <td align="center" rowspan="3">Linux开发板环境</td>        <td align="center">Linux开发板</td>        <td align="left">正点原子 i.MX6ULL Linux 阿尔法开发板</td>      </tr>    <tr>        <td align="center">uboot</td>        <td align="left">NXP官方提供的uboot，使用的uboot版本为U-Boot 2019.04</td>      </tr>    <tr>        <td align="center">linux内核</td>        <td align="left">linux-4.19.71(NXP官方提供)</td>      </tr></table>
              </div>
            </details>

<details class="folding-tag" blue><summary> 点击查看本文参考资料 </summary>
              <div class='content'>
              <table>    <tr>        <td align="center">分类</td>        <td align="center">网址</td>        <td align="center">说明</td>    </tr>    <tr>        <td align="center" rowspan="5">官方网站</td>        <td align="left"><a href="https://www.arm.com/" target="_blank">https://www.arm.com/</a></td>        <td align="left">ARM官方网站，在这里我们可以找到Cotex-Mx以及ARMVx的一些文档</td>    </tr>    <tr>        <td align="left"><a href="https://www.nxp.com.cn/" target="_blank">https://www.nxp.com.cn/ </a></td>        <td align="left">NXP官方网站</td>    </tr>    <tr>        <td align="left"><a href="https://www.nxpic.org.cn/" target="_blank">https://www.nxpic.org.cn/</a></td><td align="left">NXP 官方社区</td>    </tr>    <tr>        <td align="left"><a href="https://u-boot.readthedocs.io/en/latest/" target="_blank">https://u-boot.readthedocs.io/en/latest/</a></td><td align="left">u-boot官网</td>    </tr>    <tr>        <td align="left"><a href="https://www.kernel.org/" target="_blank">https://www.kernel.org/</a></td><td align="left">linux内核官网</td>    </tr></table>
              </div>
            </details>

<details class="folding-tag" blue><summary> 点击查看相关文件下载 </summary>
              <div class='content'>
              <table>    <tr>        <td align="center">分类</td>        <td align="center">网址</td>        <td align="center">说明</td>    </tr>    <tr>        <td align="center" rowspan="3">NXP</td>        <td align="left"><a href="https://github.com/nxp-imx" target="_blank">https://github.com/nxp-imx</a></td>        <td align="left">NXP imx开发资源GitHub组织，里边会有u-boot和linux内核的仓库</td>    </tr>    <tr>        <td align="left"><a href="https://github.com/nxp-imx/linux-imx/releases/tag/v4.19.71" target="_blank">nxp-imx/linux-imx/releases/tag/v4.19.71</a></td>        <td align="left">NXP linux内核仓库tags中的v4.19.71</td>    </tr>    <tr>        <td align="left"><a href="https://github.com/nxp-imx/uboot-imx/releases/tag/rel_imx_4.19.35_1.1.0" target="_blank">nxp-imx/uboot-imx/releases/tag/rel_imx_4.19.35_1.1.0</a></td>        <td align="left">NXP u-boot仓库tags中的rel_imx_4.19.35_1.1.0</td>    </tr>    <tr>        <td align="center" rowspan="2">I.MX6ULL</td>        <td align="left"><a href="https://www.nxp.com.cn/docs/en/data-sheet/IMX6ULLIEC.pdf" target="_blank">i.MX 6ULL Applications Processors for Industrial Products</a></td>        <td align="left">I.MX6ULL 芯片手册（datasheet，可以在线查看）</td>    </tr>    <tr>        <td align="left"><a href="https://www.nxp.com.cn/webapp/Download?colCode=IMX6ULLRM&lang_cd=zh" target="_blank">i.MX 6ULL Applications ProcessorReference Manual</a></td>        <td align="left">I.MX6ULL 参考手册（下载后才能查看，需要登录NXP官网）</td>    </tr>    <tr>        <td align="center" rowspan="2">Source Code</td>        <td align="left"><a href="https://elixir.bootlin.com/linux/latest/source" target="_blank">https://elixir.bootlin.com/linux/latest/source</a></td>        <td align="left">linux kernel源码</td>    </tr>    <tr>        <td align="left"><a href="https://elixir.bootlin.com/u-boot/latest/source" target="_blank">https://elixir.bootlin.com/u-boot/latest/source</a></td>        <td align="left">uboot源码</td>    </tr></table>
              </div>
            </details>

<h1 id="一、概述"><a href="#一、概述" class="headerlink" title="一、概述"></a><font size=3>一、概述</font></h1><h2 id="1-帮助信息"><a href="#1-帮助信息" class="headerlink" title="1. 帮助信息"></a><font size=3>1. 帮助信息</font></h2><p>我们看一下 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/Makefile#L1370">Makefile - <em>help</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">PHONY += help</span><br><span class="line"><span class="section">help:</span></span><br><span class="line"><span class="comment">#......</span></span><br><span class="line">	@echo  &#x27;* modules	  - Build all modules&#x27;</span><br><span class="line">	@echo  &#x27;  modules_install - Install all modules to INSTALL_MOD_PATH (default: /)&#x27;</span><br><span class="line"><span class="comment">#......</span></span><br><span class="line">	@echo  &#x27;  dir/file.ko     - Build module including final link&#x27;</span><br><span class="line">	@echo  &#x27;  modules_prepare - Set up for building external modules&#x27;</span><br><span class="line"><span class="comment"># ......</span></span><br></pre></td></tr></table></figure>

<h2 id="2-模块编译命令"><a href="#2-模块编译命令" class="headerlink" title="2. 模块编译命令"></a><font size=3>2. 模块编译命令</font></h2><p>从帮助信息中可以知道，我们可以通过modules等相关命令编译模块：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules -j16     <span class="comment"># 编译所有的模块</span></span><br><span class="line">make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- dir/file.ko -j16 <span class="comment"># 编译指定模块</span></span><br></pre></td></tr></table></figure>

<h1 id="二、函数说明"><a href="#二、函数说明" class="headerlink" title="二、函数说明"></a><font size=3>二、函数说明</font></h1><p>这里先来了解几个函数，后面会经常用到。</p>
<h2 id="1-cmd函数"><a href="#1-cmd函数" class="headerlink" title="1. cmd函数"></a><font size=3>1. cmd函数</font></h2><p>cmd函数定义在：<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Kbuild.include#L224">Kbuild.include - scripts&#x2F;Kbuild.include - <em>cmd</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># echo command.</span></span><br><span class="line"><span class="comment"># Short version is used, if $(quiet) equals `quiet_&#x27;, otherwise full one.</span></span><br><span class="line">echo-cmd = <span class="variable">$(<span class="built_in">if</span> $(<span class="variable">$(quiet)</span>cmd_$(1)</span>),\</span><br><span class="line">	echo &#x27;  <span class="variable">$(<span class="built_in">call</span> escsq,$(<span class="variable">$(quiet)</span>cmd_$(1)</span>))$(echo-why)&#x27;;)</span><br><span class="line"></span><br><span class="line"><span class="comment"># printing commands</span></span><br><span class="line">cmd = @$(echo-cmd) $(cmd_$(1))</span><br></pre></td></tr></table></figure>

<p>主要是它包含了<code>echo-cmd</code>，后面会经常看到，这里就单独分析一下吧。quiet就是一个前缀，<code>make V=1</code>的话，quiet为空，<code>make V=0</code>，quiet&#x3D;@。</p>
<h3 id="1-1-echo-cmd"><a href="#1-1-echo-cmd" class="headerlink" title="1.1 $(echo-cmd)"></a><font size=3>1.1 <code>$(echo-cmd)</code></font></h3><p>先看这个echo-cmd，从字面理解，应该是回显命令，而且初看也是打印命令到终端。</p>
<h4 id="1-1-1-escsq"><a href="#1-1-1-escsq" class="headerlink" title="1.1.1 escsq"></a><font size=3>1.1.1 escsq</font></h4><p>先来看一下escsq函数，它定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Kbuild.include#L32">Kbuild.include - scripts&#x2F;Kbuild.include - <em>escsq</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">###</span></span><br><span class="line"><span class="comment"># Escape single quote for use in echo statements</span></span><br><span class="line">escsq = <span class="variable">$(<span class="built_in">subst</span> <span class="variable">$(squote)</span>,&#x27;\<span class="variable">$(squote)</span>&#x27;,$1)</span></span><br></pre></td></tr></table></figure>

<p>这个subst函数是字符串替换函数，包含三个参数，第一个参数是被替换字串，第二个参数是替换字串，第三个参数是替换操作用的字串。用法如下：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$(<span class="built_in">subst</span> &lt;from&gt;,&lt;to&gt;,&lt;text&gt;)</span></span><br></pre></td></tr></table></figure>

<p>作用就是在text中将from替换成to。所以这里的含义就是在传入的参数<code>$1</code>中将<code>$(squote)</code>替换成<code>\$(squote)</code>，这个squote定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Kbuild.include#L7">Kbuild.include - scripts&#x2F;Kbuild.include - <em>squote</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">squote  := &#x27;</span><br></pre></td></tr></table></figure>

<p>所以将escsq展开就是：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">escsq = <span class="variable">$(<span class="built_in">subst</span> &#x27;,&#x27;\&#x27;&#x27;,$1)</span></span><br></pre></td></tr></table></figure>

<p>就是将<code>$1</code>中的<code>&#39;</code>替换成<code>\&#39;</code>。</p>
<h4 id="1-1-2-echo-why"><a href="#1-1-2-echo-why" class="headerlink" title="1.1.2 echo-why"></a><font size=3>1.1.2 echo-why</font></h4><p>再来看一下这个echo-why，它定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Kbuild.include#L348">Kbuild.include - scripts&#x2F;Kbuild.include - <em>echo-why</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">###</span></span><br><span class="line"><span class="comment"># why - tell why a target got built</span></span><br><span class="line"><span class="comment">#       enabled by make V=2</span></span><br><span class="line"><span class="comment">#       Output (listed in the order they are checked):</span></span><br><span class="line"><span class="comment">#          (1) - due to target is PHONY</span></span><br><span class="line"><span class="comment">#          (2) - due to target missing</span></span><br><span class="line"><span class="comment">#          (3) - due to: file1.h file2.h</span></span><br><span class="line"><span class="comment">#          (4) - due to command line change</span></span><br><span class="line"><span class="comment">#          (5) - due to missing .cmd file</span></span><br><span class="line"><span class="comment">#          (6) - due to target not in $(targets)</span></span><br><span class="line"><span class="comment"># (1) PHONY targets are always build</span></span><br><span class="line"><span class="comment"># (2) No target, so we better build it</span></span><br><span class="line"><span class="comment"># (3) Prerequisite is newer than target</span></span><br><span class="line"><span class="comment"># (4) The command line stored in the file named dir/.target.cmd</span></span><br><span class="line"><span class="comment">#     differed from actual command line. This happens when compiler</span></span><br><span class="line"><span class="comment">#     options changes</span></span><br><span class="line"><span class="comment"># (5) No dir/.target.cmd file (used to store command line)</span></span><br><span class="line"><span class="comment"># (6) No dir/.target.cmd file and target not listed in $(targets)</span></span><br><span class="line"><span class="comment">#     This is a good hint that there is a bug in the kbuild file</span></span><br><span class="line"><span class="keyword">ifeq</span> (<span class="variable">$(KBUILD_VERBOSE)</span>,2)</span><br><span class="line">why =                                                                        \</span><br><span class="line">    <span class="variable">$(<span class="built_in">if</span> $(<span class="built_in">filter</span> <span class="variable">$@</span>, <span class="variable">$(PHONY)</span>)</span>,- due to target is PHONY,                    \</span><br><span class="line">        <span class="variable">$(<span class="built_in">if</span> $(<span class="built_in">wildcard</span> <span class="variable">$@</span>)</span>,                                                 \</span><br><span class="line">            <span class="variable">$(<span class="built_in">if</span> $(<span class="built_in">strip</span> $(any-prereq)</span>),- due to: $(any-prereq),             \</span><br><span class="line">                <span class="variable">$(<span class="built_in">if</span> $(arg-check)</span>,                                           \</span><br><span class="line">                    <span class="variable">$(<span class="built_in">if</span> $(cmd_<span class="variable">$@</span>)</span>,- due to command line change,             \</span><br><span class="line">                        <span class="variable">$(<span class="built_in">if</span> $(<span class="built_in">filter</span> <span class="variable">$@</span>, <span class="variable">$(targets)</span>)</span>,                       \</span><br><span class="line">                            - due to missing .cmd file,                      \</span><br><span class="line">                            - due to <span class="variable">$(<span class="built_in">notdir</span> <span class="variable">$@</span>)</span> not in $<span class="variable">$(targets)</span>         \</span><br><span class="line">                         )                                                   \</span><br><span class="line">                     )                                                       \</span><br><span class="line">                 )                                                           \</span><br><span class="line">             ),                                                              \</span><br><span class="line">             - due to target missing                                         \</span><br><span class="line">         )                                                                   \</span><br><span class="line">     )</span><br><span class="line"></span><br><span class="line">echo-why = <span class="variable">$(<span class="built_in">call</span> escsq, $(<span class="built_in">strip</span> <span class="variable">$(why)</span>)</span>)</span><br></pre></td></tr></table></figure>

<p>这个还挺复杂的，但是最开始有注释，<code>enabled by make V=2</code>，所以这里我们直接忽略，以后用到再说吧。</p>
<h4 id="1-1-3-总结"><a href="#1-1-3-总结" class="headerlink" title="1.1.3 总结"></a><font size=3>1.1.3 总结</font></h4><p>我们简化一下echo-cmd：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># echo command.</span></span><br><span class="line"><span class="comment"># Short version is used, if $(quiet) equals `quiet_&#x27;, otherwise full one.</span></span><br><span class="line">echo-cmd = <span class="variable">$(<span class="built_in">if</span> $(<span class="variable">$(quiet)</span>cmd_$(1)</span>),\</span><br><span class="line">	echo &#x27;  <span class="variable">$(<span class="built_in">call</span> escsq,$(<span class="variable">$(quiet)</span>cmd_$(1)</span>))&#x27;;)</span><br></pre></td></tr></table></figure>

<p>其实就只是把echo-why去掉。</p>
<h3 id="1-2-cmd-1"><a href="#1-2-cmd-1" class="headerlink" title="1.2 $(cmd_$(1))"></a><font size=3>1.2 <code>$(cmd_$(1))</code></font></h3><p>这个其实没什么说的，<code>$(1)</code>就是传入的参数，替换后就是一个变量。例如<code>$(call cmd,param)</code>，这里·<code>$(1)</code>&#x3D;param，所以就是<code>$(cmd_param)</code>，随后找到cmd_param变量即可。</p>
<h3 id="1-3-cmd到底在做什么？"><a href="#1-3-cmd到底在做什么？" class="headerlink" title="1.3 cmd到底在做什么？"></a><font size=3>1.3 cmd到底在做什么？</font></h3><p>前面大概分析了两个变量，这里我们写一个demo来测试一下：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">squote  := &#x27;</span><br><span class="line">quiet   :=</span><br><span class="line"></span><br><span class="line">escsq       = <span class="variable">$(<span class="built_in">subst</span> <span class="variable">$(squote)</span>,&#x27;\<span class="variable">$(squote)</span>&#x27;,$1)</span></span><br><span class="line">echo-cmd    = <span class="variable">$(echo &#x27;  $(<span class="built_in">call</span> escsq,ls)</span>&#x27;;)</span><br><span class="line">cmd_sumucmd = ls</span><br><span class="line"></span><br><span class="line"><span class="comment"># echo command.</span></span><br><span class="line"><span class="comment"># Short version is used, if $(quiet) equals `quiet_&#x27;, otherwise full one.</span></span><br><span class="line">echo-cmd = <span class="variable">$(<span class="built_in">if</span> $(<span class="variable">$(quiet)</span>cmd_$(1)</span>),\</span><br><span class="line">	echo &#x27;  <span class="variable">$(<span class="built_in">call</span> escsq,$(<span class="variable">$(quiet)</span>cmd_$(1)</span>))&#x27;;)</span><br><span class="line"></span><br><span class="line"><span class="comment"># printing commands</span></span><br><span class="line">cmd = @$(echo-cmd) $(cmd_$(1))</span><br><span class="line"></span><br><span class="line"><span class="section">test: FORCE</span></span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> cmd,sumucmd)</span></span><br><span class="line">	$(echo-cmd) pwd</span><br><span class="line"></span><br><span class="line">PHONY+=FORCE</span><br><span class="line"><span class="section">FORCE:</span></span><br><span class="line"></span><br><span class="line"><span class="meta"><span class="keyword">.PHONY</span>: $(PHONY)</span></span><br></pre></td></tr></table></figure>

<p>然后执行，就会发现，<code>$(echo-cmd)</code>部分负责显示命令，<code>$(cmd_$(1))</code>负责执行命令：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV05-%E7%B3%BB%E7%BB%9F%E9%95%9C%E5%83%8F/LV05-03-Kernel-03-02-make-single-module/img/image-20241129000124387.png" alt="image-20241129000124387" />



<h2 id="2-wanring函数"><a href="#2-wanring函数" class="headerlink" title="2. wanring函数"></a><font size=3>2. wanring函数</font></h2><p>接下来看一个makefile的控制函数，warning，会打印当前行号和自定义文本：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$(<span class="built_in">warning</span> TEXT...)</span></span><br></pre></td></tr></table></figure>

<p>不能直接用echo吗？当然也可以，但是echo只能在target：后面的语句中使用，且前面是个TAB。这个的话，就哪里都能用。这个warning命令也可以打印变量，和echo一样。</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$(<span class="built_in">warning</span> &quot;a=$a&quot;)</span></span><br></pre></td></tr></table></figure>

<h1 id="三、make-dir-file-ko"><a href="#三、make-dir-file-ko" class="headerlink" title="三、make dir&#x2F;file.ko"></a><font size=3>三、make dir&#x2F;file.ko</font></h1><p>我们来了解一下编译指定模块，先从简单的来。这里以内核中的 drivers&#x2F;media&#x2F;i2c&#x2F;ov5640.ko 这个模块为例。</p>
<h2 id="1-ko目标"><a href="#1-ko目标" class="headerlink" title="1. %.ko目标"></a><font size=3>1. %.ko目标</font></h2><p>我们从执行的命令 make dir&#x2F;file.ko 中推测，在顶层makefile中应该存在对应的目标，我们去搜一下，会看到这个目标 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/Makefile#L1695">Makefile - <em>%ko</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">%.ko: prepare scripts FORCE</span></span><br><span class="line">	<span class="variable">$(cmd_crmodverdir)</span></span><br><span class="line">	<span class="variable">$(Q)</span><span class="variable">$(MAKE)</span> KBUILD_MODULES=<span class="variable">$(<span class="built_in">if</span> <span class="variable">$(CONFIG_MODULES)</span>,1)</span>   \</span><br><span class="line">	<span class="variable">$(build)</span>=$(build-dir) $(@:.ko=.o)</span><br><span class="line">	<span class="variable">$(Q)</span><span class="variable">$(MAKE)</span> -f <span class="variable">$(srctree)</span>/scripts/Makefile.modpost</span><br></pre></td></tr></table></figure>

<p>我们编译的命令为：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- drivers/media/i2c/ov5640.ko -j16</span><br></pre></td></tr></table></figure>

<p>所以这里的<code>%.ko</code>匹配的就是drivers&#x2F;media&#x2F;i2c&#x2F;ov5640.ko。</p>
<h3 id="1-1-cmd-crmodverdir"><a href="#1-1-cmd-crmodverdir" class="headerlink" title="1.1 cmd_crmodverdir"></a><font size=3>1.1 cmd_crmodverdir</font></h3><p>cmd_crmodverdir定义在 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/Makefile#L1717">Makefile - <em>cmd_crmodverdir</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Create temporary dir for module support files</span></span><br><span class="line"><span class="comment"># clean it up only when building all modules</span></span><br><span class="line">cmd_crmodverdir = <span class="variable">$(Q)</span>mkdir -p <span class="variable">$(MODVERDIR)</span> \</span><br><span class="line">                  <span class="variable">$(<span class="built_in">if</span> <span class="variable">$(KBUILD_MODULES)</span>,; rm -f <span class="variable">$(MODVERDIR)</span>/*)</span></span><br></pre></td></tr></table></figure>

<p>这里就不详细去找定义在哪里了，直接在%.ko目标的规则中加点打印信息看一下：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">%.ko: prepare scripts FORCE</span></span><br><span class="line">	echo <span class="string">&quot;MODVERDIR=<span class="variable">$(MODVERDIR)</span> KBUILD_MODULES=<span class="variable">$(KBUILD_MODULES)</span>&quot;</span></span><br><span class="line">	<span class="variable">$(cmd_crmodverdir)</span></span><br><span class="line">	<span class="variable">$(Q)</span><span class="variable">$(MAKE)</span> KBUILD_MODULES=<span class="variable">$(<span class="built_in">if</span> <span class="variable">$(CONFIG_MODULES)</span>,1)</span>   \</span><br><span class="line">	<span class="variable">$(build)</span>=$(build-dir) $(@:.ko=.o)</span><br><span class="line">	<span class="variable">$(Q)</span><span class="variable">$(MAKE)</span> -f <span class="variable">$(srctree)</span>/scripts/Makefile.modpost</span><br></pre></td></tr></table></figure>

<p>然后执行以下命令：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">make V=0 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean</span><br><span class="line">make V=0 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_v6_v7_defconfig</span><br><span class="line">make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- drivers/media/i2c/ov5640.ko -j16 <span class="comment"># 编译指定模块</span></span><br></pre></td></tr></table></figure>

<p>会看到以下打印信息：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">echo &quot;MODVERDIR=.tmp_versions KBUILD_MODULES=&quot;</span><br><span class="line">MODVERDIR=.tmp_versions KBUILD_MODULES=</span><br></pre></td></tr></table></figure>

<p>所以cmd_crmodverdir展开就是：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">cmd_crmodverdir = <span class="variable">$(Q)</span>mkdir -p .tmp_versions \</span><br><span class="line">                  <span class="variable">$(<span class="built_in">if</span> <span class="variable">$(KBUILD_MODULES)</span>,; rm -f .tmp_versions/*)</span></span><br></pre></td></tr></table></figure>

<p>if函数的用法如下：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$(<span class="built_in">if</span> CONDITION,THEN-PART[,ELSE-PART])</span></span><br></pre></td></tr></table></figure>

<p>if 函数的第一个参数 CONDITION表示条件判断，展开后如果非空，则条件为真，执行 THEN-PART部分；否则，如果有ELSE-PART部分，则执行ELSE-PART部分。</p>
<p>这里因为KBUILD_MODULES为空，所以这里应该执行ELSE-PART部分，但是命令中无ELSE-PART部分，所以这里就没有内容了，所以最后 </p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cmd_crmodverdir = <span class="variable">$(Q)</span>mkdir -p .tmp_versions</span><br></pre></td></tr></table></figure>

<p>这个变量最后就是在创建.tmp_versions目录了。</p>
<h3 id="1-2-KBUILD-MODULES"><a href="#1-2-KBUILD-MODULES" class="headerlink" title="1.2 KBUILD_MODULES"></a><font size=3>1.2 KBUILD_MODULES</font></h3><p>我们继续往下看KBUILD_MODULES，它的值由CONFIG_MODULES决定：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$(Q)</span><span class="variable">$(MAKE)</span> KBUILD_MODULES=<span class="variable">$(<span class="built_in">if</span> <span class="variable">$(CONFIG_MODULES)</span>,1)</span> \</span><br></pre></td></tr></table></figure>

<p>这个我们可以使用如下命令在配置后的linux内核源码中搜索一下，会在顶层源码目录中生成的.config文件中或者<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/arch/arm/configs/imx_v6_v7_defconfig#L15">imx_v6_v7_defconfig - arch&#x2F;arm&#x2F;configs&#x2F;imx_v6_v7_defconfig - <em>CONFIG_MODULES</em></a>中看到：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">CONFIG_MODULES=y</span><br></pre></td></tr></table></figure>

<p>所以KBUILD_MODULES&#x3D;1。</p>
<h3 id="1-3-build、build-dir"><a href="#1-3-build、build-dir" class="headerlink" title="1.3 build、build-dir"></a><font size=3>1.3 build、build-dir</font></h3><p>我们再看一下这个build这一行：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$(build)</span>=$(build-dir) $(@:.ko=.o)</span><br></pre></td></tr></table></figure>

<h4 id="1-3-1-build"><a href="#1-3-1-build" class="headerlink" title="1.3.1 build"></a><font size=3>1.3.1 build</font></h4><p>build定义在 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Kbuild.include#L184">Kbuild.include - scripts&#x2F;Kbuild.include - <em>build</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">###</span></span><br><span class="line"><span class="comment"># Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=</span></span><br><span class="line"><span class="comment"># Usage:</span></span><br><span class="line"><span class="comment"># $(Q)$(MAKE) $(build)=dir</span></span><br><span class="line">build := -f <span class="variable">$(srctree)</span>/scripts/Makefile.build obj</span><br></pre></td></tr></table></figure>

<h4 id="1-3-2-build-dir"><a href="#1-3-2-build-dir" class="headerlink" title="1.3.2 build-dir"></a><font size=3>1.3.2 build-dir</font></h4><p>build-dir定义在 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/Makefile#L1656">Makefile - <em>build-dir</em></a></p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Single targets are compatible with:</span></span><br><span class="line"><span class="comment"># - build with mixed source and output</span></span><br><span class="line"><span class="comment"># - build with separate output dir &#x27;make O=...&#x27;</span></span><br><span class="line"><span class="comment"># - external modules</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment">#  target-dir =&gt; where to store outputfile</span></span><br><span class="line"><span class="comment">#  build-dir  =&gt; directory in kernel source tree to use</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">ifeq</span> (<span class="variable">$(KBUILD_EXTMOD)</span>,)</span><br><span class="line">        build-dir  = <span class="variable">$(<span class="built_in">patsubst</span> %/,%,$(<span class="built_in">dir</span> <span class="variable">$@</span>)</span>)</span><br><span class="line">        target-dir = <span class="variable">$(<span class="built_in">dir</span> <span class="variable">$@</span>)</span></span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">        zap-slash=<span class="variable">$(<span class="built_in">filter</span>-out .,$(<span class="built_in">patsubst</span> %/,%,$(<span class="built_in">dir</span> <span class="variable">$@</span>)</span>))</span><br><span class="line">        build-dir  = <span class="variable">$(KBUILD_EXTMOD)</span><span class="variable">$(<span class="built_in">if</span> $(zap-slash)</span>,/$(zap-slash))</span><br><span class="line">        target-dir = <span class="variable">$(<span class="built_in">if</span> <span class="variable">$(KBUILD_EXTMOD)</span>,$(<span class="built_in">dir</span> <span class="variable">$&lt;</span>)</span>,<span class="variable">$(<span class="built_in">dir</span> <span class="variable">$@</span>)</span>)</span><br><span class="line"><span class="keyword">endif</span></span><br></pre></td></tr></table></figure>

<p>可以看到还有个变量KBUILD_EXTMOD，它定义在 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/Makefile#L179">Makefile - <em>KBUILD_EXTMOD</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">ifdef</span> SUBDIRS</span><br><span class="line">  KBUILD_EXTMOD ?= <span class="variable">$(SUBDIRS)</span></span><br><span class="line"><span class="keyword">endif</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">ifeq</span> (<span class="string">&quot;$(origin M)&quot;</span>, <span class="string">&quot;command line&quot;</span>)</span><br><span class="line">  KBUILD_EXTMOD := <span class="variable">$(M)</span></span><br><span class="line"><span class="keyword">endif</span></span><br></pre></td></tr></table></figure>

<p>SUBDIRS是没有定义的，所以KBUILD_EXTMOD的值来自于命令行的M参数，而前面我们编译单独模块的时候没有M参数，所以这里KBUILD_EXTMOD为空。所以build-dir值如下：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">build-dir  = <span class="variable">$(<span class="built_in">patsubst</span> %/,%,$(<span class="built_in">dir</span> <span class="variable">$@</span>)</span>)</span><br></pre></td></tr></table></figure>

<p><code>$@</code>就是目标，就是前面的<code>%.ko</code>，根据编译命令：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- drivers/media/i2c/ov5640.ko -j16</span><br></pre></td></tr></table></figure>

<p>我们知道<code>$@</code>&#x3D;drivers&#x2F;media&#x2F;i2c&#x2F;ov5640.ko。所以有：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">build-dir  = <span class="variable">$(<span class="built_in">patsubst</span> %/,%,$(<span class="built_in">dir</span> drivers/media/i2c/ov5640.ko)</span>)</span><br></pre></td></tr></table></figure>

<p>dir函数的功能是从文件名序列 names 中取出目录部分，如果names 中没有 &#x2F; ，取出的值为 .&#x2F; 。返回值为目录部分，指的是最后一个反斜杠之前的部分。如果没有反斜杠将返回 .&#x2F;。所以我们取消dir函数：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">build-dir  = <span class="variable">$(<span class="built_in">patsubst</span> %/,%,drivers/media/i2c/)</span></span><br></pre></td></tr></table></figure>

<p>patsubst函数用法为：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$(<span class="built_in">patsubst</span> pattern,replacement,text)</span></span><br></pre></td></tr></table></figure>

<p><code>pattern</code>：要匹配的模式。<code>replacement</code>：替换后的字符串。<code>text</code>：要进行模式替换的文本。所以这里最后的结果是：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">build-dir  = drivers/media/i2c</span><br></pre></td></tr></table></figure>

<h4 id="1-3-3-ko-o"><a href="#1-3-3-ko-o" class="headerlink" title="1.3.3 $(@:.ko=.o)"></a><font size=3>1.3.3 <code>$(@:.ko=.o)</code></font></h4><p><code>$(@:.ko=.o)</code>是是 Makefile 中的一个变量替换语法，用于将目标文件中的后缀 <code>.ko</code> 替换为 <code>.o</code>。前面我们知道<code>$@</code>&#x3D;drivers&#x2F;media&#x2F;i2c&#x2F;ov5640.ko，所以这里就是：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">$(drivers/media/i2c/ov5640.ko:.ko=.o)</span></span><br></pre></td></tr></table></figure>

<p>替换后就是：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">drivers/media/i2c/ov5640.o</span><br></pre></td></tr></table></figure>

<h4 id="1-3-4-命令展开"><a href="#1-3-4-命令展开" class="headerlink" title="1.3.4 命令展开"></a><font size=3>1.3.4 命令展开</font></h4><p>我们已经分析了每一个变量，这里这条命令：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$(build)</span>=$(build-dir) $(@:.ko=.o)</span><br></pre></td></tr></table></figure>

<p>我们展开如下：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">-f <span class="variable">$(srctree)</span>/scripts/Makefile.build obj=drivers/media/i2c drivers/media/i2c/ov5640.o</span><br></pre></td></tr></table></figure>

<p>这里其实是半句，其实和前面的KBUILD_MODULES加在一起才是一条完整命令：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$(Q)</span><span class="variable">$(MAKE)</span> KBUILD_MODULES=<span class="variable">$(<span class="built_in">if</span> <span class="variable">$(CONFIG_MODULES)</span>,1)</span>   \</span><br><span class="line"><span class="variable">$(build)</span>=$(build-dir) $(@:.ko=.o)</span><br></pre></td></tr></table></figure>

<p>我们一起展开：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">@make KBUILD_MODULES=1 -f <span class="variable">$(srctree)</span>/scripts/Makefile.build obj=drivers/media/i2c drivers/media/i2c/ov5640.o</span><br></pre></td></tr></table></figure>

<h3 id="1-4-ko规则展开"><a href="#1-4-ko规则展开" class="headerlink" title="1.4 %.ko规则展开"></a><font size=3>1.4 %.ko规则展开</font></h3><p>上面我们对每一部分进行了分析，我们来展开一下<code>%.ko</code>的规则：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">%.ko: prepare scripts FORCE</span></span><br><span class="line">	<span class="variable">$(cmd_crmodverdir)</span></span><br><span class="line">	<span class="variable">$(Q)</span><span class="variable">$(MAKE)</span> KBUILD_MODULES=<span class="variable">$(<span class="built_in">if</span> <span class="variable">$(CONFIG_MODULES)</span>,1)</span>   \</span><br><span class="line">	<span class="variable">$(build)</span>=$(build-dir) $(@:.ko=.o)</span><br><span class="line">	<span class="variable">$(Q)</span><span class="variable">$(MAKE)</span> -f <span class="variable">$(srctree)</span>/scripts/Makefile.modpost</span><br></pre></td></tr></table></figure>

<p>展开后为：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">drivers/media/i2c/ov5640.ko: prepare scripts FORCE</span></span><br><span class="line">	<span class="variable">$(Q)</span>mkdir -p .tmp_versions</span><br><span class="line">	<span class="variable">$(Q)</span>make KBUILD_MODULES=1 -f <span class="variable">$(srctree)</span>/scripts/Makefile.build obj=drivers/media/i2c drivers/media/i2c/ov5640.o</span><br><span class="line">	<span class="variable">$(Q)</span>make -f <span class="variable">$(srctree)</span>/scripts/Makefile.modpost</span><br></pre></td></tr></table></figure>

<p>srctree这个值为<code>.</code>，定义在 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/Makefile#L190">Makefile - <em>srctree</em></a></p>
<h2 id="2-Makefile-build"><a href="#2-Makefile-build" class="headerlink" title="2. Makefile.build "></a><font size=3>2. Makefile.build </font></h2><p>上面已经把<code>%.ko</code>目标展开了，接下来我们来分析这个命令：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$(Q)</span>make KBUILD_MODULES=1 -f ./scripts/Makefile.build obj=drivers/media/i2c drivers/media/i2c/ov5640.o</span><br></pre></td></tr></table></figure>

<p><code>make -f</code> 命令用于指定 Makefile 文件的名称。默认情况下，<code>make</code> 会查找名为 <code>Makefile</code> 或 <code>makefile</code> 的文件。项目中使用了不同的文件名，可以通过 <code>-f</code> 选项来指定。所以这里，很显然，就是指定make命令使用的文件为Makefile.build。</p>
<p>这个命令传入KBUILD_MODULES和obj参数。并且指定了目标为drivers&#x2F;media&#x2F;i2c&#x2F;ov5640.o。</p>
<h3 id="2-1-obj与src"><a href="#2-1-obj与src" class="headerlink" title="2.1 obj与src"></a><font size=3>2.1 obj与src</font></h3><p>先来看两个变量obj和src，这个obj是调用<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.build#L6">Makefile.build - scripts&#x2F;Makefile.build</a>文件的时候传进来的，src定义在：<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.build#L6">Makefile.build - scripts&#x2F;Makefile.build - <em>src</em></a></p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">src := <span class="variable">$(obj)</span></span><br></pre></td></tr></table></figure>

<p>可以看到其实src和obj是相等的。</p>
<h3 id="2-2-obj-o目标"><a href="#2-2-obj-o目标" class="headerlink" title="2.2 $(obj)/%.o目标"></a><font size=3>2.2 <code>$(obj)/%.o</code>目标</font></h3><h4 id="2-2-1-匹配哪一个目标？"><a href="#2-2-1-匹配哪一个目标？" class="headerlink" title="2.2.1 匹配哪一个目标？"></a><font size=3>2.2.1 匹配哪一个目标？</font></h4><p><code>$(obj)/%.o</code>这个目标在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.build">Makefile.build - scripts&#x2F;Makefile.build</a>文件中有三处定义：</p>
<ul>
<li>（1）<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.build#L302">Makefile.build - scripts&#x2F;Makefile.build - <em><code>$(obj)/%.o</code></em></a>：</li>
</ul>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Built-in and composite module parts</span></span><br><span class="line"><span class="variable">$(obj)</span>/%.o: <span class="variable">$(src)</span>/%.c <span class="variable">$(recordmcount_source)</span> <span class="variable">$(objtool_dep)</span> FORCE</span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> cmd,force_checksrc)</span></span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> if_changed_rule,cc_o_c)</span></span><br></pre></td></tr></table></figure>

<ul>
<li>（2）<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.build#L308">Makefile.build - scripts&#x2F;Makefile.build -  <em><code>$(single-used-m): $(obj)/%.o</code></em></a></li>
</ul>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Single-part modules are special since we need to mark them in $(MODVERDIR)</span></span><br><span class="line"></span><br><span class="line"><span class="section">$(single-used-m): <span class="variable">$(obj)</span>/%.o: <span class="variable">$(src)</span>/%.c <span class="variable">$(recordmcount_source)</span> <span class="variable">$(objtool_dep)</span> FORCE</span></span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> cmd,force_checksrc)</span></span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> if_changed_rule,cc_o_c)</span></span><br><span class="line">	@&#123; echo $(@:.o=.ko); echo <span class="variable">$@</span>; \</span><br><span class="line">	   <span class="variable">$(cmd_undef_syms)</span>; &#125; &gt; <span class="variable">$(MODVERDIR)</span>/$(@F:.o=.mod)</span><br></pre></td></tr></table></figure>

<ul>
<li>（3）<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.build#L402">Makefile.build - scripts&#x2F;Makefile.build -  <em><code>$(obj)/%.o</code></em></a></li>
</ul>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$(obj)</span>/%.o: <span class="variable">$(src)</span>/%.S <span class="variable">$(objtool_dep)</span> FORCE</span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> if_changed_rule,as_o_S)</span></span><br></pre></td></tr></table></figure>

<p>那我们使用的这个编译命令：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- drivers/media/i2c/ov5640.ko -j16</span><br></pre></td></tr></table></figure>

<p>到底匹配的哪个哪个目标？我们可以看到（3）这个其实是跟汇编文件相关的，可以看一下 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/drivers/media/i2c">i2c - drivers&#x2F;media&#x2F;i2c</a> 这个目录下，其实是没有汇编文件的，所以还是匹配的上面.c相关的规则。还是在（1）和（2）中，那是哪个？先看一下这个single-used-m，它是定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.lib#L48">Makefile.lib - scripts&#x2F;Makefile.lib - <em>single-used-m</em></a>，这个文件在 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.build#L54">Makefile.build - scripts&#x2F;Makefile.build</a> 文件中被调用。具体是什么，这里就暂时先不深入去追了。直接加打印信息吧，两个位置都加：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Built-in and composite module parts</span></span><br><span class="line"><span class="variable">$(obj)</span>/%.o: <span class="variable">$(src)</span>/%.c <span class="variable">$(recordmcount_source)</span> <span class="variable">$(objtool_dep)</span> FORCE</span><br><span class="line">	echo <span class="string">&quot;info(1) obj=<span class="variable">$(obj)</span> src=<span class="variable">$(src)</span> <span class="variable">$@</span> <span class="variable">$&lt;</span>&quot;</span></span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> cmd,force_checksrc)</span></span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> if_changed_rule,cc_o_c)</span></span><br><span class="line">	</span><br><span class="line"><span class="comment"># ......</span></span><br><span class="line"></span><br><span class="line"><span class="section">$(single-used-m): <span class="variable">$(obj)</span>/%.o: <span class="variable">$(src)</span>/%.c <span class="variable">$(recordmcount_source)</span> <span class="variable">$(objtool_dep)</span> FORCE</span></span><br><span class="line">	echo <span class="string">&quot;info(2) single-used-m=$(single-used-m) obj=<span class="variable">$(obj)</span> src=<span class="variable">$(src)</span> <span class="variable">$@</span> <span class="variable">$&lt;</span>&quot;</span>	</span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> cmd,force_checksrc)</span></span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> if_changed_rule,cc_o_c)</span></span><br><span class="line">	@&#123; echo $(@:.o=.ko); echo <span class="variable">$@</span>; \</span><br><span class="line">	   <span class="variable">$(cmd_undef_syms)</span>; &#125; &gt; <span class="variable">$(MODVERDIR)</span>/$(@F:.o=.mod)</span><br></pre></td></tr></table></figure>

<p>然后我们执行：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">make V=0 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean</span><br><span class="line">make V=0 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_v6_v7_defconfig</span><br><span class="line">make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- drivers/media/i2c/ov5640.ko -j16 <span class="comment"># 编译指定模块</span></span><br></pre></td></tr></table></figure>

<p>可以看到有以下打印信息：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">echo &quot;info(1) obj=scripts/mod src=scripts/mod scripts/mod/empty.o scripts/mod/empty.c&quot;</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">......</span></span><br><span class="line">info(1) obj=scripts/mod src=scripts/mod scripts/mod/empty.o scripts/mod/empty.c</span><br><span class="line"></span><br><span class="line">mkdir -p .tmp_versions</span><br><span class="line">make KBUILD_MODULES=1   \</span><br><span class="line">-f ./scripts/Makefile.build obj=drivers/media/i2c drivers/media/i2c/ov5640.o</span><br><span class="line">echo &quot;info(2) single-used-m=drivers/media/i2c/adv7180.o drivers/media/i2c/ov5640.o obj=drivers/media/i2c src=drivers/media/i2c drivers/media/i2c/ov5640.o drivers/media/i2c/ov5640.c&quot;</span><br><span class="line">info(2) single-used-m=drivers/media/i2c/adv7180.o drivers/media/i2c/ov5640.o obj=drivers/media/i2c src=drivers/media/i2c drivers/media/i2c/ov5640.o drivers/media/i2c/ov5640.c</span><br></pre></td></tr></table></figure>

<p>所以这里其实两个地方都用的到了，但是完成ov5640.c文件编译的目标其实是（2）：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Single-part modules are special since we need to mark them in $(MODVERDIR)</span></span><br><span class="line"></span><br><span class="line"><span class="section">$(single-used-m): <span class="variable">$(obj)</span>/%.o: <span class="variable">$(src)</span>/%.c <span class="variable">$(recordmcount_source)</span> <span class="variable">$(objtool_dep)</span> FORCE</span></span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> cmd,force_checksrc)</span></span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> if_changed_rule,cc_o_c)</span></span><br><span class="line">	@&#123; echo $(@:.o=.ko); echo <span class="variable">$@</span>; \</span><br><span class="line">	   <span class="variable">$(cmd_undef_syms)</span>; &#125; &gt; <span class="variable">$(MODVERDIR)</span>/$(@F:.o=.mod)</span><br></pre></td></tr></table></figure>

<h4 id="2-2-2-call-cmd-force-checksrc"><a href="#2-2-2-call-cmd-force-checksrc" class="headerlink" title="2.2.2 $(call cmd,force_checksrc)"></a><font size=3>2.2.2 <code>$(call cmd,force_checksrc)</code></font></h4><p>接下来我们来看这个命令：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$(<span class="built_in">call</span> cmd,force_checksrc)</span></span><br></pre></td></tr></table></figure>

<p>这个其实应该很熟悉了，cmd函数定义在：<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Kbuild.include#L224">Kbuild.include - scripts&#x2F;Kbuild.include - <em>cmd</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># echo command.</span></span><br><span class="line"><span class="comment"># Short version is used, if $(quiet) equals `quiet_&#x27;, otherwise full one.</span></span><br><span class="line">echo-cmd = <span class="variable">$(<span class="built_in">if</span> $(<span class="variable">$(quiet)</span>cmd_$(1)</span>),\</span><br><span class="line">	echo &#x27;  <span class="variable">$(<span class="built_in">call</span> escsq,$(<span class="variable">$(quiet)</span>cmd_$(1)</span>))$(echo-why)&#x27;;)</span><br><span class="line"></span><br><span class="line"><span class="comment"># printing commands</span></span><br><span class="line">cmd = @$(echo-cmd) $(cmd_$(1))</span><br></pre></td></tr></table></figure>

<p>直接看<code>$(cmd_$(1))</code>吧，这个<code>$(1)</code>&#x3D;force_checksrc，所以这里其实调用的就是cmd_force_checksrc，它定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.build#L85">Makefile.build - scripts&#x2F;Makefile.build - <em>cmd_force_checksrc</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Linus&#x27; kernel sanity checking tool</span></span><br><span class="line"><span class="keyword">ifneq</span> (<span class="variable">$(KBUILD_CHECKSRC)</span>,0)</span><br><span class="line">  <span class="keyword">ifeq</span> (<span class="variable">$(KBUILD_CHECKSRC)</span>,2)</span><br><span class="line">    quiet_cmd_force_checksrc = CHECK   <span class="variable">$&lt;</span></span><br><span class="line">          cmd_force_checksrc = <span class="variable">$(CHECK)</span> <span class="variable">$(CHECKFLAGS)</span> <span class="variable">$(c_flags)</span> <span class="variable">$&lt;</span> ;</span><br><span class="line">  <span class="keyword">else</span></span><br><span class="line">      quiet_cmd_checksrc     = CHECK   <span class="variable">$&lt;</span></span><br><span class="line">            cmd_checksrc     = <span class="variable">$(CHECK)</span> <span class="variable">$(CHECKFLAGS)</span> <span class="variable">$(c_flags)</span> <span class="variable">$&lt;</span> ;</span><br><span class="line">  <span class="keyword">endif</span></span><br><span class="line"><span class="keyword">endif</span></span><br></pre></td></tr></table></figure>

<p>KBUILD_CHECKSRC定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/Makefile#L162">Makefile - <em>KBUILD_CHECKSRC</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Call a source code checker (by default, &quot;sparse&quot;) as part of the</span></span><br><span class="line"><span class="comment"># C compilation.</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># Use &#x27;make C=1&#x27; to enable checking of only re-compiled files.</span></span><br><span class="line"><span class="comment"># Use &#x27;make C=2&#x27; to enable checking of *all* source files, regardless</span></span><br><span class="line"><span class="comment"># of whether they are re-compiled or not.</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># See the file &quot;Documentation/dev-tools/sparse.rst&quot; for more details,</span></span><br><span class="line"><span class="comment"># including where to get the &quot;sparse&quot; utility.</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">ifeq</span> (<span class="string">&quot;$(origin C)&quot;</span>, <span class="string">&quot;command line&quot;</span>)</span><br><span class="line">  KBUILD_CHECKSRC = <span class="variable">$(C)</span></span><br><span class="line"><span class="keyword">endif</span></span><br><span class="line"><span class="keyword">ifndef</span> KBUILD_CHECKSRC</span><br><span class="line">  KBUILD_CHECKSRC = 0</span><br><span class="line"><span class="keyword">endif</span></span><br></pre></td></tr></table></figure>

<p>这个其实就是代码检查，由于我们没有传入C参数（注意这里的C和-C是不一样的含义，这里C为变量名，是要赋值的，-C是指定一个源码目录，不一样的），就没有定义KBUILD_CHECKSRC，这里的KBUILD_CHECKSRC就是0，所以cmd_force_checksrc就为空。</p>
<h4 id="2-2-3-call-if-changed-rule-cc-o-c"><a href="#2-2-3-call-if-changed-rule-cc-o-c" class="headerlink" title="2.2.3 $(call if_changed_rule,cc_o_c)"></a><font size=3>2.2.3 <code>$(call if_changed_rule,cc_o_c)</code></font></h4><p>if_changed_rule定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Kbuild.include#L304">Kbuild.include - scripts&#x2F;Kbuild.include - <em>if_changed_rule</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Usage: $(call if_changed_rule,foo)</span></span><br><span class="line"><span class="comment"># Will check if $(cmd_foo) or any of the prerequisites changed,</span></span><br><span class="line"><span class="comment"># and if so will execute $(rule_foo).</span></span><br><span class="line">if_changed_rule = <span class="variable">$(<span class="built_in">if</span> $(<span class="built_in">strip</span> $(any-prereq)</span> $(arg-check) ),                 \</span><br><span class="line">	@set -e;                                                             \</span><br><span class="line">	$(rule_$(1)), @:)</span><br></pre></td></tr></table></figure>

<p><code>set -e</code> 是一个在 shell 脚本中常用的命令，用于在脚本中启用“遇到错误即退出”的行为。具体来说，当脚本中的任何命令返回非零状态时，脚本会立即终止执行。</p>
<p>strip函数是去掉变量值两端的空白字符（空格和制表符），if是判断后面去掉空白字符的变量值是否为空，当any-prereq和arg-check有一个非空，if就成立，就执行<code>$(rule_$(1))</code>。否则就执行<code>@:</code>，在shell中<code>:</code>是一个特殊的命令，它实际上是一个内建命令，用于执行空操作。</p>
<p>这里我们第一次编译的时候any-prereq和arg-check肯定至少有一个非空，这两个变量就不多了解了，主要后面看执行的<code>$(rule_$(1))</code>。</p>
<h5 id="2-2-3-1-any-prereq"><a href="#2-2-3-1-any-prereq" class="headerlink" title="2.2.3.1 any-prereq"></a><font size=3>2.2.3.1 any-prereq</font></h5><p>any-prereq定义在 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Kbuild.include#L256">Kbuild.include - scripts&#x2F;Kbuild.include - <em>any-prereq</em></a></p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Find any prerequisites that is newer than target or that does not exist.</span></span><br><span class="line"><span class="comment"># PHONY targets skipped in both cases.</span></span><br><span class="line">any-prereq = <span class="variable">$(<span class="built_in">filter</span>-out <span class="variable">$(PHONY)</span>,<span class="variable">$?</span>)</span> <span class="variable">$(<span class="built_in">filter</span>-out <span class="variable">$(PHONY)</span> $(<span class="built_in">wildcard</span> <span class="variable">$^</span>)</span>,<span class="variable">$^</span>)</span><br></pre></td></tr></table></figure>

<h5 id="2-2-3-2-arg-check"><a href="#2-2-3-2-arg-check" class="headerlink" title="2.2.3.2 arg-check"></a><font size=3>2.2.3.2 arg-check</font></h5><p>arg-check定义在 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Kbuild.include#L238">Kbuild.include - scripts&#x2F;Kbuild.include - <em>arg-check</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">ifneq</span> (<span class="variable">$(KBUILD_NOCMDDEP)</span>,1)</span><br><span class="line"><span class="comment"># Check if both arguments are the same including their order. Result is empty</span></span><br><span class="line"><span class="comment"># string if equal. User may override this check using make KBUILD_NOCMDDEP=1</span></span><br><span class="line">arg-check = <span class="variable">$(<span class="built_in">filter</span>-out $(<span class="built_in">subst</span> <span class="variable">$(space)</span>,<span class="variable">$(space_escape)</span>,$(<span class="built_in">strip</span> $(cmd_<span class="variable">$@</span>)</span>)), \</span><br><span class="line">                         <span class="variable">$(<span class="built_in">subst</span> <span class="variable">$(space)</span>,<span class="variable">$(space_escape)</span>,$(<span class="built_in">strip</span> $(cmd_$1)</span>)))</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">arg-check = <span class="variable">$(<span class="built_in">if</span> $(<span class="built_in">strip</span> $(cmd_<span class="variable">$@</span>)</span>),,1)</span><br><span class="line"><span class="keyword">endif</span></span><br></pre></td></tr></table></figure>

<h5 id="2-2-3-3-rule-1"><a href="#2-2-3-3-rule-1" class="headerlink" title="2.2.3.3 $(rule_$(1))"></a><font size=3>2.2.3.3 <code>$(rule_$(1))</code></font></h5><p><code>$(1)</code>就是cc_o_c，所以这里展开就是：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$(rule_$(1)) = <span class="variable">$(rule_cc_o_c)</span></span><br></pre></td></tr></table></figure>

<p>rule_cc_o_c定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.build#L279">Makefile.build - scripts&#x2F;Makefile.build - <em>rule_cc_o_c</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">define</span> rule_cc_o_c</span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> echo-cmd,checksrc)</span> <span class="variable">$(cmd_checksrc)</span>			  \</span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> cmd_and_fixdep,cc_o_c)</span>					  \</span><br><span class="line">	<span class="variable">$(cmd_checkdoc)</span>							  \</span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> echo-cmd,objtool)</span> <span class="variable">$(cmd_objtool)</span>				  \</span><br><span class="line">	<span class="variable">$(cmd_modversions_c)</span>						  \</span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> echo-cmd,record_mcount)</span> <span class="variable">$(cmd_record_mcount)</span></span><br><span class="line"><span class="keyword">endef</span></span><br></pre></td></tr></table></figure>

<p>其实到这里，<code>$(obj)/%.o</code>目标的规则就展开基本结束了。我们后面继续深入这个rule_cc_o_c。</p>
<h2 id="3-rule-cc-o-c函数"><a href="#3-rule-cc-o-c函数" class="headerlink" title="3. rule_cc_o_c函数"></a><font size=3>3. rule_cc_o_c函数</font></h2><p>为什么单独写呢？因为标题嵌套太深啦，哈哈哈。这里我们详细再把这个rule_cc_o_c分析一下。这个rule_cc_o_c，前面已经找到它定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.build#L279">Makefile.build - scripts&#x2F;Makefile.build - <em>rule_cc_o_c</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">define</span> rule_cc_o_c</span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> echo-cmd,checksrc)</span> <span class="variable">$(cmd_checksrc)</span>			  \</span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> cmd_and_fixdep,cc_o_c)</span>					  \</span><br><span class="line">	<span class="variable">$(cmd_checkdoc)</span>							  \</span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> echo-cmd,objtool)</span> <span class="variable">$(cmd_objtool)</span>				  \</span><br><span class="line">	<span class="variable">$(cmd_modversions_c)</span>						  \</span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> echo-cmd,record_mcount)</span> <span class="variable">$(cmd_record_mcount)</span></span><br><span class="line"><span class="keyword">endef</span></span><br></pre></td></tr></table></figure>

<h3 id="3-1-checksrc"><a href="#3-1-checksrc" class="headerlink" title="3.1 checksrc"></a><font size=3>3.1 checksrc</font></h3><p>我们来看一下这一行<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.build#L280">Makefile.build - scripts&#x2F;Makefile.build </a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$(<span class="built_in">call</span> echo-cmd,checksrc)</span> <span class="variable">$(cmd_checksrc)</span></span><br></pre></td></tr></table></figure>

<h4 id="3-1-1-cmd-checksrc"><a href="#3-1-1-cmd-checksrc" class="headerlink" title="3.1.1 $(cmd_checksrc)"></a><font size=3>3.1.1 <code>$(cmd_checksrc)</code></font></h4><p>先看这个cmd_checksrc，它定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.build#L91">Makefile.build - scripts&#x2F;Makefile.build - <em>cmd_checksrc</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Linus&#x27; kernel sanity checking tool</span></span><br><span class="line"><span class="keyword">ifneq</span> (<span class="variable">$(KBUILD_CHECKSRC)</span>,0)</span><br><span class="line">  <span class="keyword">ifeq</span> (<span class="variable">$(KBUILD_CHECKSRC)</span>,2)</span><br><span class="line">    quiet_cmd_force_checksrc = CHECK   <span class="variable">$&lt;</span></span><br><span class="line">          cmd_force_checksrc = <span class="variable">$(CHECK)</span> <span class="variable">$(CHECKFLAGS)</span> <span class="variable">$(c_flags)</span> <span class="variable">$&lt;</span> ;</span><br><span class="line">  <span class="keyword">else</span></span><br><span class="line">      quiet_cmd_checksrc     = CHECK   <span class="variable">$&lt;</span></span><br><span class="line">            cmd_checksrc     = <span class="variable">$(CHECK)</span> <span class="variable">$(CHECKFLAGS)</span> <span class="variable">$(c_flags)</span> <span class="variable">$&lt;</span> ;</span><br><span class="line">  <span class="keyword">endif</span></span><br><span class="line"><span class="keyword">endif</span></span><br></pre></td></tr></table></figure>

<p>会发现，这里其实和我们分析的 二、make dir&#x2F;file.ko这一节中的2.2.2 <code>$(call cmd,force_checksrc)</code>这部分逻辑一样的，取决于KBUILD_CHECKSRC的值，我们前面分析了，使用make C&#x3D;2这样的命令这里才会有定义，所以这里也是为空。</p>
<h4 id="3-1-2-call-echo-cmd-checksrc"><a href="#3-1-2-call-echo-cmd-checksrc" class="headerlink" title="3.1.2 $(call echo-cmd,checksrc)"></a><font size=3>3.1.2 <code>$(call echo-cmd,checksrc)</code></font></h4><p>echo-cmd定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Kbuild.include#L220">Kbuild.include - scripts&#x2F;Kbuild.include - <em>echo-cmd</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># echo command.</span></span><br><span class="line"><span class="comment"># Short version is used, if $(quiet) equals `quiet_&#x27;, otherwise full one.</span></span><br><span class="line">echo-cmd = <span class="variable">$(<span class="built_in">if</span> $(<span class="variable">$(quiet)</span>cmd_$(1)</span>),\</span><br><span class="line">	echo &#x27;  <span class="variable">$(<span class="built_in">call</span> escsq,$(<span class="variable">$(quiet)</span>cmd_$(1)</span>))$(echo-why)&#x27;;)</span><br></pre></td></tr></table></figure>

<p>这里的<code>$(1)</code>&#x3D;checksrc，quiet定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/Makefile#L81">Makefile - <em>quiet</em></a>，分析一下就可以知道，当我们执行<code>make V=1</code>的时候，这里quiet为空，当执行<code>make V=0</code>的时候，quiet&#x3D;quiet_。所以这里展开是：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">echo-cmd = <span class="variable">$(<span class="built_in">if</span> <span class="variable">$(cmd_checksrc)</span>,\</span></span><br><span class="line"><span class="variable">	echo &#x27;  $(<span class="built_in">call</span> escsq,$(<span class="variable">$(quiet)</span>cmd_$(1)</span>))$(echo-why)&#x27;;)</span><br><span class="line"><span class="comment"># 或者</span></span><br><span class="line">echo-cmd = <span class="variable">$(<span class="built_in">if</span> <span class="variable">$(quiet_cmd_checksrc)</span>,\</span></span><br><span class="line"><span class="variable">	echo &#x27;  $(<span class="built_in">call</span> escsq,$(<span class="variable">$(quiet)</span>cmd_$(1)</span>))$(echo-why)&#x27;;)</span><br></pre></td></tr></table></figure>

<p>cmd_check和quiet_cmd_checksrc都定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.build#L92">Makefile.build - <em>cmd_check</em></a>这里，还是和二、make dir&#x2F;file.ko这一节中的2.2.2 <code>$(call cmd,force_checksrc)</code>一样，由于我们没有传入C参数的值，这里都是空的。</p>
<h4 id="3-1-3-总结"><a href="#3-1-3-总结" class="headerlink" title="3.1.3 总结"></a><font size=3>3.1.3 总结</font></h4><p>由于没有传入make C&#x3D;2其他值，这里并没有开启代码检查。所以<code>$(call echo-cmd,checksrc) </code>和<code>$(cmd_checksrc)</code>都为空。</p>
<h3 id="3-2-call-cmd-and-fixdep-cc-o-c"><a href="#3-2-call-cmd-and-fixdep-cc-o-c" class="headerlink" title="3.2 $(call cmd_and_fixdep,cc_o_c)"></a><font size=3>3.2 <code>$(call cmd_and_fixdep,cc_o_c)</code></font></h3><p>接下来来看一下这个命令：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$(<span class="built_in">call</span> cmd_and_fixdep,cc_o_c)</span></span><br></pre></td></tr></table></figure>

<p>这个命令是调用函数cmd_and_fixdep，传入参数为cc_o_c。</p>
<p>cmd_and_fixdep定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Kbuild.include#L271">Kbuild.include - scripts&#x2F;Kbuild.include - <em>cmd_and_fixdep</em></a>，它有两个定义，通过CONFIG_TRIM_UNUSED_KSYMS选择不同的命令：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">ifndef</span> CONFIG_TRIM_UNUSED_KSYMS</span><br><span class="line"><span class="comment"># (1)</span></span><br><span class="line">cmd_and_fixdep =                                                             \</span><br><span class="line"><span class="comment">#......</span></span><br><span class="line"><span class="keyword">else</span></span><br><span class="line"><span class="comment">#......</span></span><br><span class="line"><span class="comment"># (2)</span></span><br><span class="line">cmd_and_fixdep =                                                             \</span><br><span class="line"><span class="comment"># ......</span></span><br><span class="line"><span class="keyword">endif</span></span><br></pre></td></tr></table></figure>

<p>我们搜一下这个CONFIG_TRIM_UNUSED_KSYMS配置项，会发现是没有的，所以这里执行（1）的命令：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">cmd_and_fixdep =                                                             \</span><br><span class="line">	$(echo-cmd) $(cmd_$(1));                                             \</span><br><span class="line">	scripts/basic/fixdep <span class="variable">$(depfile)</span> <span class="variable">$@</span> &#x27;$(make-cmd)&#x27; &gt; $(dot-target).tmp;\</span><br><span class="line">	rm -f <span class="variable">$(depfile)</span>;                                                    \</span><br><span class="line">	mv -f $(dot-target).tmp $(dot-target).cmd;</span><br></pre></td></tr></table></figure>

<p><code>$(1)</code>&#x3D;cc_o_c,所以这里是：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">cmd_and_fixdep =                                                             \</span><br><span class="line">	$(echo-cmd) <span class="variable">$(cmd_cc_o_c)</span>;                                             \</span><br><span class="line">	scripts/basic/fixdep <span class="variable">$(depfile)</span> <span class="variable">$@</span> &#x27;$(make-cmd)&#x27; &gt; $(dot-target).tmp;\</span><br><span class="line">	rm -f <span class="variable">$(depfile)</span>;                                                    \</span><br><span class="line">	mv -f $(dot-target).tmp $(dot-target).cmd;</span><br></pre></td></tr></table></figure>

<h4 id="3-2-1-echo-cmd"><a href="#3-2-1-echo-cmd" class="headerlink" title="3.2.1 $(echo-cmd)"></a><font size=3>3.2.1 <code>$(echo-cmd)</code></font></h4><p>echo-cmd定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Kbuild.include#L220">Kbuild.include - <em>echo-cmd</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># echo command.</span></span><br><span class="line"><span class="comment"># Short version is used, if $(quiet) equals `quiet_&#x27;, otherwise full one.</span></span><br><span class="line">echo-cmd = <span class="variable">$(<span class="built_in">if</span> $(<span class="variable">$(quiet)</span>cmd_$(1)</span>),\</span><br><span class="line">	echo &#x27;  <span class="variable">$(<span class="built_in">call</span> escsq,$(<span class="variable">$(quiet)</span>cmd_$(1)</span>))$(echo-why)&#x27;;)</span><br></pre></td></tr></table></figure>

<p>根据前面分析的这里就是：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">echo-cmd = <span class="variable">$(<span class="built_in">if</span> <span class="variable">$(cmd_cc_o_c)</span>,\</span></span><br><span class="line"><span class="variable">	echo &#x27;  $(<span class="built_in">call</span> escsq,$(<span class="variable">$(quiet)</span>cmd_$(1)</span>))$(echo-why)&#x27;;)</span><br><span class="line"><span class="comment"># 或者</span></span><br><span class="line">echo-cmd = <span class="variable">$(<span class="built_in">if</span> <span class="variable">$(quiet_cmd_cc_o_c)</span>,\</span></span><br><span class="line"><span class="variable">	echo &#x27;  $(<span class="built_in">call</span> escsq,$(<span class="variable">$(quiet)</span>cmd_$(1)</span>))$(echo-why)&#x27;;)</span><br></pre></td></tr></table></figure>

<p>这里按<code>make V=1</code>的结果进行的分析，那我们要找的就是cmd_cc_o_c，其实最终他们执行的都是一样的，只不过就是打印信息的区别。cmd_cc_o_c定义在这个位置：<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.build#L164">Makefile.build - scripts&#x2F;Makefile.build - <em>cmd_cc_o_c</em></a></p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># C (.c) files</span></span><br><span class="line"><span class="comment"># The C file is compiled and updated dependency information is generated.</span></span><br><span class="line"><span class="comment"># (See cmd_cc_o_c + relevant part of rule_cc_o_c)</span></span><br><span class="line"></span><br><span class="line">quiet_cmd_cc_o_c = CC <span class="variable">$(quiet_modtag)</span>  <span class="variable">$@</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">ifndef</span> CONFIG_MODVERSIONS</span><br><span class="line">cmd_cc_o_c = <span class="variable">$(CC)</span> <span class="variable">$(c_flags)</span> -c -o <span class="variable">$@</span> <span class="variable">$&lt;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">else</span></span><br><span class="line"><span class="comment">#......</span></span><br><span class="line">cmd_cc_o_c = <span class="variable">$(CC)</span> <span class="variable">$(c_flags)</span> -c -o $(@D)/.tmp_$(@F) <span class="variable">$&lt;</span></span><br><span class="line"><span class="comment"># ......</span></span><br><span class="line"><span class="keyword">endif</span></span><br></pre></td></tr></table></figure>

<p>我们搜索一下CONFIG_MODVERSIONS，发现在imx_v6_v7_defconfig和.config中有定义：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">CONFIG_MODVERSIONS=y</span><br></pre></td></tr></table></figure>

<p>所以这里就是：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cmd_cc_o_c = <span class="variable">$(CC)</span> <span class="variable">$(c_flags)</span> -c -o $(@D)/.tmp_$(@F) <span class="variable">$&lt;</span></span><br></pre></td></tr></table></figure>

<p>显然是非空的，这里if成立，就是：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">echo-cmd = echo &#x27;  <span class="variable">$(<span class="built_in">call</span> escsq,$(<span class="variable">$(quiet)</span>cmd_$(1)</span>))$(echo-why)&#x27;;</span><br></pre></td></tr></table></figure>

<h4 id="3-2-2-cmd-cc-o-c"><a href="#3-2-2-cmd-cc-o-c" class="headerlink" title="3.2.2 $(cmd_cc_o_c)"></a><font size=3>3.2.2 <code>$(cmd_cc_o_c)</code></font></h4><p>上一小节其实已经分析完了，cmd_cc_o_c定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.build#L164">Makefile.build - scripts&#x2F;Makefile.build - <em>cmd_cc_o_c</em></a>，的值为</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cmd_cc_o_c = <span class="variable">$(CC)</span> <span class="variable">$(c_flags)</span> -c -o $(@D)/.tmp_$(@F) <span class="variable">$&lt;</span></span><br></pre></td></tr></table></figure>

<ul>
<li><p><code>$(@D)</code>表示”<code>$@</code>“的目录部分（不以斜杠作为结尾） ，如果”<code>$@</code>“值是”dir&#x2F;foo.o”，那么”<code>$(@D)</code>“就是”dir”，而如果”<code>$@</code>“中没有包含斜杠的话，其值就是”.”（当前目录） 。</p>
</li>
<li><p><code>$(@F)</code>表示”<code>$@</code>“的文件部分，如果”<code>$@</code>“值是”dir&#x2F;foo.o”，那么”<code>$(@F</code>)”就是”foo.o”，”<code>$(@F)</code>“相当于函数”<code>$(notdir $@)</code>“</p>
</li>
</ul>
<p>所以这里其实就是把c文件编译成o的地方。</p>
<h4 id="3-2-3-echo-cmd-cmd-1-做了什么？"><a href="#3-2-3-echo-cmd-cmd-1-做了什么？" class="headerlink" title="3.2.3 $(echo-cmd) $(cmd_$(1))做了什么？"></a><font size=3>3.2.3 <code>$(echo-cmd) $(cmd_$(1))</code>做了什么？</font></h4><p>上面已经单独分析了这两个变量，但是好像也不清楚具体是做了什么，里面有一些变量还是没有办法确定，前面简单展开了<code>cmd_and_fixdep</code>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">cmd_and_fixdep =                                                             \</span><br><span class="line">	$(echo-cmd) <span class="variable">$(cmd_cc_o_c)</span>;                                             \</span><br><span class="line">	scripts/basic/fixdep <span class="variable">$(depfile)</span> <span class="variable">$@</span> &#x27;$(make-cmd)&#x27; &gt; $(dot-target).tmp;\</span><br><span class="line">	rm -f <span class="variable">$(depfile)</span>;                                                    \</span><br><span class="line">	mv -f $(dot-target).tmp $(dot-target).cmd;</span><br></pre></td></tr></table></figure>

<p>我们这里再继续展开一下第2行：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">cmd_and_fixdep =                                                             \</span><br><span class="line">	echo &#x27;  <span class="variable">$(<span class="built_in">call</span> escsq,$(<span class="variable">$(quiet)</span>cmd_$(1)</span>))$(echo-why)&#x27;; <span class="variable">$(CC)</span> <span class="variable">$(c_flags)</span> -c -o $(@D)/.tmp_$(@F) <span class="variable">$&lt;</span>;                                             \</span><br><span class="line">	scripts/basic/fixdep <span class="variable">$(depfile)</span> <span class="variable">$@</span> &#x27;$(make-cmd)&#x27; &gt; $(dot-target).tmp;\</span><br><span class="line">	rm -f <span class="variable">$(depfile)</span>;                                                    \</span><br><span class="line">	mv -f $(dot-target).tmp $(dot-target).cmd;</span><br></pre></td></tr></table></figure>

<p>在这里加个打印信息吧<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Kbuild.include#L271">Kbuild.include - scripts&#x2F;Kbuild.include - <em>cmd_and_fixdep</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">cmd_and_fixdep =                                                             \</span><br><span class="line">	echo <span class="string">&quot;cmd_and_fixdep info CC=<span class="variable">$(CC)</span> c_flags=<span class="variable">$(c_flags)</span> @D=$(@D) @F=$(@F) <span class="variable">$&lt;</span>&quot;</span>;\</span><br><span class="line">	$(echo-cmd) <span class="variable">$(cmd_cc_o_c)</span>;                                             \</span><br><span class="line">	scripts/basic/fixdep <span class="variable">$(depfile)</span> <span class="variable">$@</span> &#x27;$(make-cmd)&#x27; &gt; $(dot-target).tmp;\</span><br><span class="line">	rm -f <span class="variable">$(depfile)</span>;                                                    \</span><br><span class="line">	mv -f $(dot-target).tmp $(dot-target).cmd;</span><br></pre></td></tr></table></figure>

<p>然后执行以下命令：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">make V=0 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean</span><br><span class="line">make V=0 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_v6_v7_defconfig</span><br><span class="line">make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- drivers/media/i2c/ov5640.ko -j16</span><br></pre></td></tr></table></figure>

<p>其实cmd_and_fixdep命令就是用来编译C文件的，所以调用的地方有很多，我们加的打印信息也会出现很多次，我们找这个：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">mkdir -p .tmp_versions</span><br><span class="line">make KBUILD_MODULES=1   \</span><br><span class="line">-f ./scripts/Makefile.build obj=drivers/media/i2c drivers/media/i2c/ov5640.o</span><br><span class="line">echo &quot;info(2) single-used-m=drivers/media/i2c/adv7180.o drivers/media/i2c/ov5640.o obj=drivers/media/i2c src=drivers/media/i2c drivers/media/i2c/ov5640.o drivers/media/i2c/ov5640.c&quot;</span><br><span class="line">info(2) single-used-m=drivers/media/i2c/adv7180.o drivers/media/i2c/ov5640.o obj=drivers/media/i2c src=drivers/media/i2c drivers/media/i2c/ov5640.o drivers/media/i2c/ov5640.c</span><br><span class="line">cmd_and_fixdep info CC=arm-linux-gnueabihf-gcc c_flags=-Wp,-MD,drivers/media/i2c/.ov5640.o.d  -nostdinc -isystem /opt/gcc-linaro-arm-linux-gnueabihf-4.9-2014.09_linux/bin/../lib/gcc/arm-linux-gnueabihf/4.9.2/include -I./arch/arm/include -I./arch/arm/include/generated  -I./include -I./arch/arm/include/uapi -I./arch/arm/include/generated/uapi -I./include/uapi -I./include/generated/uapi -include ./include/linux/kconfig.h -include ./include/linux/compiler_types.h -D__KERNEL__ -mlittle-endian -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -fshort-wchar -Werror-implicit-function-declaration -Wno-format-security -std=gnu89 -fno-PIE -fno-dwarf2-cfi-asm -fno-omit-frame-pointer -mapcs -mno-sched-prolog -fno-ipa-sra -mabi=aapcs-linux -mfpu=vfp -marm -Wa,-mno-warn-deprecated -D__LINUX_ARM_ARCH__=6 -march=armv6k -mtune=arm1136j-s -msoft-float -Uarm -fno-delete-null-pointer-checks -O2 --param=allow-store-data-races=0 -Wframe-larger-than=1024 -fstack-protector-strong -Wno-unused-but-set-variable -fno-omit-frame-pointer -fno-optimize-sibling-calls -fno-var-tracking-assignments -Wdeclaration-after-statement -Wno-pointer-sign -fno-strict-overflow -fno-merge-all-constants -fmerge-constants -fno-stack-check -fconserve-stack -Werror=implicit-int -Werror=strict-prototypes -Werror=date-time  -DMODULE  -DKBUILD_BASENAME=&#x27;ov5640&#x27; -DKBUILD_MODNAME=&#x27;ov5640&#x27; @D=drivers/media/i2c @F=ov5640.o drivers/media/i2c/ov5640.c</span><br></pre></td></tr></table></figure>

<p>info(2)这里是前面 二、make dir&#x2F;file.ko部分的2.2 <code>$(obj)/%.o</code>目标 这一个小节添加的，刚好帮我们定位我们所需要的 cmd_and_fixdep info，整理一下：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">cmd_and_fixdep info：</span><br><span class="line">CC=arm-linux-gnueabihf-gcc </span><br><span class="line">c_flags=-Wp,-MD,drivers/media/i2c/.ov5640.o.d  -nostdinc -isystem /opt/gcc-linaro-arm-linux-gnueabihf-4.9-2014.09_linux/bin/../lib/gcc/arm-linux-gnueabihf/4.9.2/include -I./arch/arm/include -I./arch/arm/include/generated  -I./include -I./arch/arm/include/uapi -I./arch/arm/include/generated/uapi -I./include/uapi -I./include/generated/uapi -include ./include/linux/kconfig.h -include ./include/linux/compiler_types.h -D__KERNEL__ -mlittle-endian -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -fshort-wchar -Werror-implicit-function-declaration -Wno-format-security -std=gnu89 -fno-PIE -fno-dwarf2-cfi-asm -fno-omit-frame-pointer -mapcs -mno-sched-prolog -fno-ipa-sra -mabi=aapcs-linux -mfpu=vfp -marm -Wa,-mno-warn-deprecated -D__LINUX_ARM_ARCH__=6 -march=armv6k -mtune=arm1136j-s -msoft-float -Uarm -fno-delete-null-pointer-checks -O2 --param=allow-store-data-races=0 -Wframe-larger-than=1024 -fstack-protector-strong -Wno-unused-but-set-variable -fno-omit-frame-pointer -fno-optimize-sibling-calls -fno-var-tracking-assignments -Wdeclaration-after-statement -Wno-pointer-sign -fno-strict-overflow -fno-merge-all-constants -fmerge-constants -fno-stack-check -fconserve-stack -Werror=implicit-int -Werror=strict-prototypes -Werror=date-time  -DMODULE  -DKBUILD_BASENAME=&#x27;ov5640&#x27; -DKBUILD_MODNAME=&#x27;ov5640&#x27; </span><br><span class="line">@D=drivers/media/i2c </span><br><span class="line">@F=ov5640.o </span><br><span class="line">drivers/media/i2c/ov5640.c</span><br></pre></td></tr></table></figure>

<p>所以总的来说，<code>$(echo-cmd) $(cmd_$(1))</code>完成了drivers&#x2F;media&#x2F;i2c&#x2F;ov5640.c到drivers&#x2F;media&#x2F;i2c&#x2F;ov5640.o的编译。</p>
<h3 id="3-3-cmd-checkdoc"><a href="#3-3-cmd-checkdoc" class="headerlink" title="3.3 $(cmd_checkdoc)"></a><font size=3>3.3 <code>$(cmd_checkdoc)</code></font></h3><p>接下来看这个cmd_checkdoc，它是定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.build#L97">Makefile.build - scripts&#x2F;Makefile.build - <em>cmd_checkdoc</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">ifneq</span> (<span class="variable">$(KBUILD_ENABLE_EXTRA_GCC_CHECKS)</span>,)</span><br><span class="line">  cmd_checkdoc = <span class="variable">$(srctree)</span>/scripts/kernel-doc -none <span class="variable">$&lt;</span> ;</span><br><span class="line"><span class="keyword">endif</span></span><br></pre></td></tr></table></figure>

<p>我们搜索一下这个KBUILD_ENABLE_EXTRA_GCC_CHECKS，会发现它定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.extrawarn#L17">Makefile.extrawarn - scripts&#x2F;Makefile.extrawarn - <em>KBUILD_ENABLE_EXTRA_GCC_CHECKS</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">ifeq</span> (<span class="string">&quot;$(origin W)&quot;</span>, <span class="string">&quot;command line&quot;</span>)</span><br><span class="line">  <span class="keyword">export</span> KBUILD_ENABLE_EXTRA_GCC_CHECKS := <span class="variable">$(W)</span></span><br><span class="line"><span class="keyword">endif</span></span><br></pre></td></tr></table></figure>

<p>可以看到这里是从命令行读取W参数，但是我们编译的时候没有加入这个参数，所以这里为空。</p>
<p><a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.extrawarn#L17">Makefile.extrawarn - scripts&#x2F;Makefile.extrawarn</a>这个文件是在顶层<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/Makefile#L842">Makefile</a>中被包含。这里ifneq就是判断参数是否不相等，这里判断的是KBUILD_ENABLE_EXTRA_GCC_CHECKS与0是否不相等嫌显然这里不成立，所以cmd_checkdoc为空。这条命令相当于没有。</p>
<h3 id="3-4-objtool"><a href="#3-4-objtool" class="headerlink" title="3.4 objtool"></a><font size=3>3.4 objtool</font></h3><p>我们继续看这条命令<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.build#L283">Makefile.build - scripts&#x2F;Makefile.build</a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$(<span class="built_in">call</span> echo-cmd,objtool)</span> <span class="variable">$(cmd_objtool)</span></span><br></pre></td></tr></table></figure>

<h4 id="3-4-1-cmd-objtool"><a href="#3-4-1-cmd-objtool" class="headerlink" title="3.4.1 $(cmd_objtool)"></a><font size=3>3.4.1 <code>$(cmd_objtool)</code></font></h4><p>先看这个cmd_objtool，它定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.build#L264">Makefile.build - scripts&#x2F;Makefile.build - <em>cmd_objtool</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># &#x27;OBJECT_FILES_NON_STANDARD := y&#x27;: skip objtool checking for a directory</span></span><br><span class="line"><span class="comment"># &#x27;OBJECT_FILES_NON_STANDARD_foo.o := &#x27;y&#x27;: skip objtool checking for a file</span></span><br><span class="line"><span class="comment"># &#x27;OBJECT_FILES_NON_STANDARD_foo.o := &#x27;n&#x27;: override directory skip for a file</span></span><br><span class="line">cmd_objtool = <span class="variable">$(<span class="built_in">if</span> $(<span class="built_in">patsubst</span> y%,, \</span></span><br><span class="line"><span class="variable">	$(OBJECT_FILES_NON_STANDARD_<span class="variable">$(basetarget)</span>.o)</span><span class="variable">$(OBJECT_FILES_NON_STANDARD)</span>n), \</span><br><span class="line">	<span class="variable">$(__objtool_obj)</span> <span class="variable">$(objtool_args)</span> <span class="string">&quot;<span class="variable">$(objtool_o)</span>&quot;</span>;)</span><br><span class="line">objtool_obj = <span class="variable">$(<span class="built_in">if</span> $(<span class="built_in">patsubst</span> y%,, \</span></span><br><span class="line"><span class="variable">	$(OBJECT_FILES_NON_STANDARD_<span class="variable">$(basetarget)</span>.o)</span><span class="variable">$(OBJECT_FILES_NON_STANDARD)</span>n), \</span><br><span class="line">	<span class="variable">$(__objtool_obj)</span>)</span><br></pre></td></tr></table></figure>

<p>这里直接加个打印信息看下结果吧，就在这个位置加：<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.build#L283">Makefile.build - scripts&#x2F;Makefile.build</a></p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">define</span> rule_cc_o_c</span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> echo-cmd,checksrc)</span> <span class="variable">$(cmd_checksrc)</span>			  \</span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> cmd_and_fixdep,cc_o_c)</span>					  \</span><br><span class="line">	<span class="variable">$(cmd_checkdoc)</span>							  \</span><br><span class="line">	<span class="variable">$(<span class="built_in">warning</span> cmd_objtool=<span class="variable">$(cmd_objtool)</span>)</span> \</span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> echo-cmd,objtool)</span> <span class="variable">$(cmd_objtool)</span>				  \</span><br><span class="line">	<span class="variable">$(cmd_modversions_c)</span>						  \</span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> echo-cmd,record_mcount)</span> <span class="variable">$(cmd_record_mcount)</span></span><br><span class="line"><span class="keyword">endef</span></span><br></pre></td></tr></table></figure>

<p>在这里我加了<code>$(warning &lt;text&gt;)</code>函数，它不用像echo一样有限制，echo只能在target：后面的语句中使用，且前面是个TAB。用这个函数还可以打印出行号（不过这个行号感觉和文件中的有些区别，因为Makefile是先替替换函数内容然后执行，所以可能意义也不大）。值然后执行以下命令：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">make V=0 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean</span><br><span class="line">make V=0 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_v6_v7_defconfig</span><br><span class="line">make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- drivers/media/i2c/ov5640.ko -j16 <span class="comment"># 编译指定模块</span></span><br></pre></td></tr></table></figure>

<p>会看到如下打印信息：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">scripts/Makefile.build:311: cmd_objtool=</span></span><br></pre></td></tr></table></figure>

<p>所以在单独编译这个模块的时候这里为空，就先不管了。</p>
<h4 id="3-4-2-call-echo-cmd-objtool"><a href="#3-4-2-call-echo-cmd-objtool" class="headerlink" title="3.4.2 $(call echo-cmd,objtool)"></a><font size=3>3.4.2 <code>$(call echo-cmd,objtool)</code></font></h4><p>再来看一下这个echo-cmd函数，前面分析过的，echo-cmd定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Kbuild.include#L220">Kbuild.include - scripts&#x2F;Kbuild.include - <em>echo-cmd</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># echo command.</span></span><br><span class="line"><span class="comment"># Short version is used, if $(quiet) equals `quiet_&#x27;, otherwise full one.</span></span><br><span class="line">echo-cmd = <span class="variable">$(<span class="built_in">if</span> $(<span class="variable">$(quiet)</span>cmd_$(1)</span>),\</span><br><span class="line">	echo &#x27;  <span class="variable">$(<span class="built_in">call</span> escsq,$(<span class="variable">$(quiet)</span>cmd_$(1)</span>))$(echo-why)&#x27;;)</span><br></pre></td></tr></table></figure>

<p>这里的<code>$(1)</code>&#x3D;objtool，quiet定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/Makefile#L81">Makefile - <em>quiet</em></a>，分析一下就可以知道，当我们执行<code>make V=1</code>的时候，这里quiet为空，当执行<code>make V=0</code>的时候，quiet&#x3D;quiet_。所以这里展开是：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">echo-cmd = <span class="variable">$(<span class="built_in">if</span> <span class="variable">$(cmd_objtool)</span>,\</span></span><br><span class="line"><span class="variable">	echo &#x27;  $(<span class="built_in">call</span> escsq,$(<span class="variable">$(quiet)</span>cmd_$(1)</span>))$(echo-why)&#x27;;)</span><br><span class="line"><span class="comment"># 或者</span></span><br><span class="line">echo-cmd = <span class="variable">$(<span class="built_in">if</span> <span class="variable">$(quiet_cmd_objtool)</span>,\</span></span><br><span class="line"><span class="variable">	echo &#x27;  $(<span class="built_in">call</span> escsq,$(<span class="variable">$(quiet)</span>cmd_$(1)</span>))$(echo-why)&#x27;;)</span><br></pre></td></tr></table></figure>

<p>前面其实分析过cmd_objtool这个了，它是为空，所以这里也不会有什么信息。</p>
<h4 id="3-4-3-总结"><a href="#3-4-3-总结" class="headerlink" title="3.4.3 总结"></a><font size=3>3.4.3 总结</font></h4><p>前面已经分析了<code>$(call echo-cmd,objtool)</code>和 <code>$(cmd_objtool)</code>，他们都是为空，所以这行就不用管了，我们在打印信息里其实也会发现不会有相关的内容出现。</p>
<h3 id="3-5-cmd-modversions-c"><a href="#3-5-cmd-modversions-c" class="headerlink" title="3.5 $(cmd_modversions_c)"></a><font size=3>3.5 <code>$(cmd_modversions_c)</code></font></h3><p>接下来看一下这个cmd_modversions_c，它定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.build#L188">Makefile.build - scripts&#x2F;Makefile.build - <em>cmd_modversions_c</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">cmd_modversions_c =								\</span><br><span class="line">	if <span class="variable">$(OBJDUMP)</span> -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then		\</span><br><span class="line">		<span class="variable">$(<span class="built_in">call</span> cmd_gensymtypes_c,<span class="variable">$(KBUILD_SYMTYPES)</span>,$(@:.o=.symtypes)</span>)	\</span><br><span class="line">		    &gt; $(@D)/.tmp_$(@F:.o=.ver);					\</span><br><span class="line">										\</span><br><span class="line">		<span class="variable">$(LD)</span> <span class="variable">$(KBUILD_LDFLAGS)</span> -r -o <span class="variable">$@</span> $(@D)/.tmp_$(@F) 		\</span><br><span class="line">			-T $(@D)/.tmp_$(@F:.o=.ver);				\</span><br><span class="line">		rm -f $(@D)/.tmp_$(@F) $(@D)/.tmp_$(@F:.o=.ver);		\</span><br><span class="line">	<span class="keyword">else</span>									\</span><br><span class="line">		mv -f $(@D)/.tmp_$(@F) <span class="variable">$@</span>;					\</span><br><span class="line">	fi;</span><br></pre></td></tr></table></figure>

<p>又是一堆的变量，这里直接接打印信息吧：<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.build#L284">Makefile.build - scripts&#x2F;Makefile.build</a></p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">define</span> rule_cc_o_c</span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> echo-cmd,checksrc)</span> <span class="variable">$(cmd_checksrc)</span>			  \</span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> cmd_and_fixdep,cc_o_c)</span>					  \</span><br><span class="line">	<span class="variable">$(cmd_checkdoc)</span>							  \</span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> echo-cmd,objtool)</span> <span class="variable">$(cmd_objtool)</span>				  \</span><br><span class="line">	<span class="variable">$(<span class="built_in">warning</span> cmd_modversions_c=<span class="variable">$(cmd_modversions_c)</span>)</span> \</span><br><span class="line">	<span class="variable">$(cmd_modversions_c)</span>						  \</span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> echo-cmd,record_mcount)</span> <span class="variable">$(cmd_record_mcount)</span></span><br><span class="line"><span class="keyword">endef</span></span><br></pre></td></tr></table></figure>

<p>然后继续执行以下命令：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">make V=0 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean</span><br><span class="line">make V=0 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_v6_v7_defconfig</span><br><span class="line">make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- drivers/media/i2c/ov5640.ko -j16 # 编译指定模块</span><br></pre></td></tr></table></figure>

<p>会看到如下打印信息：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">scripts/Makefile.build:311: cmd_modversions_c=if arm-linux-gnueabihf-objdump -h drivers/media/i2c/.tmp_ov5640.o | grep -q __ksymtab; then arm-linux-gnueabihf-gcc -E -D__GENKSYMS__ -Wp,-MD,drivers/media/i2c/.ov5640.o.d  -nostdinc -isystem /opt/gcc-linaro-arm-linux-gnueabihf-4.9-2014.09_linux/bin/../lib/gcc/arm-linux-gnueabihf/4.9.2/include -I./arch/arm/include -I./arch/arm/include/generated  -I./include -I./arch/arm/include/uapi -I./arch/arm/include/generated/uapi -I./include/uapi -I./include/generated/uapi -include ./include/linux/kconfig.h -include ./include/linux/compiler_types.h -D__KERNEL__ -mlittle-endian -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -fshort-wchar -Werror-implicit-function-declaration -Wno-format-security -std=gnu89 -fno-PIE -fno-dwarf2-cfi-asm -fno-omit-frame-pointer -mapcs -mno-sched-prolog -fno-ipa-sra -mabi=aapcs-linux -mfpu=vfp -marm -Wa,-mno-warn-deprecated -D__LINUX_ARM_ARCH__=6 -march=armv6k -mtune=arm1136j-s -msoft-float -Uarm -fno-delete-null-pointer-checks -O2 --param=allow-store-data-races=0 -Wframe-larger-than=1024 -fstack-protector-strong -Wno-unused-but-set-variable -fno-omit-frame-pointer -fno-optimize-sibling-calls -fno-var-tracking-assignments -Wdeclaration-after-statement -Wno-pointer-sign -fno-strict-overflow -fno-merge-all-constants -fmerge-constants -fno-stack-check -fconserve-stack -Werror=implicit-int -Werror=strict-prototypes -Werror=date-time  -DMODULE  -DKBUILD_BASENAME=&#x27;&quot;ov5640&quot;&#x27; -DKBUILD_MODNAME=&#x27;&quot;ov5640&quot;&#x27; drivers/media/i2c/ov5640.c | scripts/genksyms/genksyms    -r /dev/null &gt; drivers/media/i2c/.tmp_ov5640.ver; arm-linux-gnueabihf-ld  -EL -r -o drivers/media/i2c/ov5640.o drivers/media/i2c/.tmp_ov5640.o -T drivers/media/i2c/.tmp_ov5640.ver; rm -f drivers/media/i2c/.tmp_ov5640.o drivers/media/i2c/.tmp_ov5640.ver; else mv -f drivers/media/i2c/.tmp_ov5640.o drivers/media/i2c/ov5640.o; fi;</span><br></pre></td></tr></table></figure>

<p>整理一下就是：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">cmd_modversions_c=</span><br><span class="line">if arm-linux-gnueabihf-objdump -h drivers/media/i2c/.tmp_ov5640.o | grep -q __ksymtab; then </span><br><span class="line">	arm-linux-gnueabihf-gcc -E -D__GENKSYMS__ -Wp,-MD,drivers/media/i2c/.ov5640.o.d  -nostdinc -isystem /opt/gcc-linaro-arm-linux-gnueabihf-4.9-2014.09_linux/bin/../lib/gcc/arm-linux-gnueabihf/4.9.2/include -I./arch/arm/include -I./arch/arm/include/generated  -I./include -I./arch/arm/include/uapi -I./arch/arm/include/generated/uapi -I./include/uapi -I./include/generated/uapi -include ./include/linux/kconfig.h -include ./include/linux/compiler_types.h -D__KERNEL__ -mlittle-endian -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -fshort-wchar -Werror-implicit-function-declaration -Wno-format-security -std=gnu89 -fno-PIE -fno-dwarf2-cfi-asm -fno-omit-frame-pointer -mapcs -mno-sched-prolog -fno-ipa-sra -mabi=aapcs-linux -mfpu=vfp -marm -Wa,-mno-warn-deprecated -D__LINUX_ARM_ARCH__=6 -march=armv6k -mtune=arm1136j-s -msoft-float -Uarm -fno-delete-null-pointer-checks -O2 --param=allow-store-data-races=0 -Wframe-larger-than=1024 -fstack-protector-strong -Wno-unused-but-set-variable -fno-omit-frame-pointer -fno-optimize-sibling-calls -fno-var-tracking-assignments -Wdeclaration-after-statement -Wno-pointer-sign -fno-strict-overflow -fno-merge-all-constants -fmerge-constants -fno-stack-check -fconserve-stack -Werror=implicit-int -Werror=strict-prototypes -Werror=date-time  -DMODULE  -DKBUILD_BASENAME=&#x27;&quot;ov5640&quot;&#x27; -DKBUILD_MODNAME=&#x27;&quot;ov5640&quot;&#x27; drivers/media/i2c/ov5640.c | scripts/genksyms/genksyms    -r /dev/null &gt; drivers/media/i2c/.tmp_ov5640.ver; arm-linux-gnueabihf-ld  -EL -r -o drivers/media/i2c/ov5640.o drivers/media/i2c/.tmp_ov5640.o -T drivers/media/i2c/.tmp_ov5640.ver; </span><br><span class="line">	rm -f drivers/media/i2c/.tmp_ov5640.o drivers/media/i2c/.tmp_ov5640.ver; </span><br><span class="line">else </span><br><span class="line">	mv -f drivers/media/i2c/.tmp_ov5640.o drivers/media/i2c/ov5640.o; </span><br><span class="line">fi;</span><br></pre></td></tr></table></figure>

<h3 id="3-6-record-mcount"><a href="#3-6-record-mcount" class="headerlink" title="3.6 record_mcount"></a><font size=3>3.6 record_mcount</font></h3><p>接下来看一下 rule_cc_o_c 的最后一条命令：<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.build#L285">Makefile.build - scripts&#x2F;Makefile.build</a></p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">define</span> rule_cc_o_c</span><br><span class="line"><span class="comment">#......</span></span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> echo-cmd,record_mcount)</span> <span class="variable">$(cmd_record_mcount)</span></span><br><span class="line"><span class="keyword">endef</span></span><br></pre></td></tr></table></figure>

<h4 id="3-6-1-cmd-record-mcount"><a href="#3-6-1-cmd-record-mcount" class="headerlink" title="3.6.1 $(cmd_record_mcount)"></a><font size=3>3.6.1 <code>$(cmd_record_mcount)</code></font></h4><p>cmd_record_mcount定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.build#L227">Makefile.build - scripts&#x2F;Makefile.build - <em>cmd_record_mcount</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">cmd_record_mcount =						\</span><br><span class="line">	if [ <span class="string">&quot;$(findstring <span class="variable">$(CC_FLAGS_FTRACE)</span>,<span class="variable">$(_c_flags)</span>)&quot;</span> =	\</span><br><span class="line">	     <span class="string">&quot;<span class="variable">$(CC_FLAGS_FTRACE)</span>&quot;</span> ]; then			\</span><br><span class="line">		<span class="variable">$(sub_cmd_record_mcount)</span>			\</span><br><span class="line">	fi;</span><br></pre></td></tr></table></figure>

<p>还是省点事，直接在这里加打印信息：<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.build#L285">Makefile.build - scripts&#x2F;Makefile.build</a></p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">define rule_cc_o_c</span><br><span class="line"><span class="meta prompt_">	$</span><span class="language-bash">(call echo-cmd,checksrc) $(cmd_checksrc)			  \</span></span><br><span class="line"><span class="language-bash">	$(call cmd_and_fixdep,cc_o_c)					  \</span></span><br><span class="line"><span class="language-bash">	$(cmd_checkdoc)							  \</span></span><br><span class="line"><span class="language-bash">	$(call echo-cmd,objtool) $(cmd_objtool)				  \</span></span><br><span class="line"><span class="language-bash">	$(cmd_modversions_c)						  \</span></span><br><span class="line"><span class="language-bash">	$(warning record_mcount=$(record_mcount)) \</span></span><br><span class="line"><span class="language-bash">	$(call echo-cmd,record_mcount) $(cmd_record_mcount)</span></span><br><span class="line">endef</span><br></pre></td></tr></table></figure>

<p>然后还是执行：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">make V=0 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean</span><br><span class="line">make V=0 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_v6_v7_defconfig</span><br><span class="line">make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- drivers/media/i2c/ov5640.ko -j16 # 编译指定模块</span><br></pre></td></tr></table></figure>

<p>会看到以下打印信息：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">mkdir -p .tmp_versions</span><br><span class="line">make KBUILD_MODULES=1   \</span><br><span class="line">-f ./scripts/Makefile.build obj=drivers/media/i2c drivers/media/i2c/ov5640.o</span><br><span class="line">scripts/Makefile.build:311: record_mcount=</span><br></pre></td></tr></table></figure>

<p>可以看到这里还是为空。</p>
<h4 id="3-6-2-call-echo-cmd-record-mcount"><a href="#3-6-2-call-echo-cmd-record-mcount" class="headerlink" title="3.6.2 $(call echo-cmd,record_mcount)"></a><font size=3>3.6.2 <code>$(call echo-cmd,record_mcount)</code></font></h4><p>接下来看一下<code>$(call echo-cmd,record_mcount)</code>,再来看一下这个echo-cmd函数，前面分析过的，echo-cmd定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Kbuild.include#L220">Kbuild.include - scripts&#x2F;Kbuild.include - <em>echo-cmd</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># echo command.</span></span><br><span class="line"><span class="comment"># Short version is used, if $(quiet) equals `quiet_&#x27;, otherwise full one.</span></span><br><span class="line">echo-cmd = <span class="variable">$(<span class="built_in">if</span> $(<span class="variable">$(quiet)</span>cmd_$(1)</span>),\</span><br><span class="line">	echo &#x27;  <span class="variable">$(<span class="built_in">call</span> escsq,$(<span class="variable">$(quiet)</span>cmd_$(1)</span>))$(echo-why)&#x27;;)</span><br></pre></td></tr></table></figure>

<p>这里的<code>$(1)</code>&#x3D;record_mcount，quiet定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/Makefile#L81">Makefile - <em>quiet</em></a>，分析一下就可以知道，当我们执行<code>make V=1</code>的时候，这里quiet为空，当执行<code>make V=0</code>的时候，quiet&#x3D;quiet_。所以这里展开是：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">echo-cmd = <span class="variable">$(<span class="built_in">if</span> <span class="variable">$(cmd_record_mcount)</span>,\</span></span><br><span class="line"><span class="variable">	echo &#x27;  $(<span class="built_in">call</span> escsq,$(<span class="variable">$(quiet)</span>cmd_$(1)</span>))$(echo-why)&#x27;;)</span><br><span class="line"><span class="comment"># 或者</span></span><br><span class="line">echo-cmd = <span class="variable">$(<span class="built_in">if</span> <span class="variable">$(quiet_cmd_record_mcount)</span>,\</span></span><br><span class="line"><span class="variable">	echo &#x27;  $(<span class="built_in">call</span> escsq,$(<span class="variable">$(quiet)</span>cmd_$(1)</span>))$(echo-why)&#x27;;)</span><br></pre></td></tr></table></figure>

<p>前面其实分析过record_mcount这个了，它是为空，所以这里也不会有什么信息。</p>
<h4 id="3-6-3-总结"><a href="#3-6-3-总结" class="headerlink" title="3.6.3 总结"></a><font size=3>3.6.3 总结</font></h4><p>综上所述，这里这行命令其实也是空。</p>
<h3 id="3-7-rule-cc-o-c总结"><a href="#3-7-rule-cc-o-c总结" class="headerlink" title="3.7 rule_cc_o_c总结"></a><font size=3>3.7 rule_cc_o_c总结</font></h3><p>经过以上分析，我们再来看一下这个函数：Makefile.build - scripts&#x2F;Makefile.build - <em>rule_cc_o_c</em>](<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.build#L279)%EF%BC%9A">https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.build#L279)：</a></p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">define</span> rule_cc_o_c</span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> echo-cmd,checksrc)</span> <span class="variable">$(cmd_checksrc)</span>			  \</span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> cmd_and_fixdep,cc_o_c)</span>					  \</span><br><span class="line">	<span class="variable">$(cmd_checkdoc)</span>							  \</span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> echo-cmd,objtool)</span> <span class="variable">$(cmd_objtool)</span>				  \</span><br><span class="line">	<span class="variable">$(cmd_modversions_c)</span>						  \</span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> echo-cmd,record_mcount)</span> <span class="variable">$(cmd_record_mcount)</span></span><br><span class="line"><span class="keyword">endef</span></span><br></pre></td></tr></table></figure>

<p>在我们单独编译drivers&#x2F;media&#x2F;i2c&#x2F;ov5640.ko的时候，这个函数里面其实可以简化为：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">define</span> rule_cc_o_c</span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> cmd_and_fixdep,cc_o_c)</span>					  \</span><br><span class="line"><span class="keyword">endef</span></span><br></pre></td></tr></table></figure>

<p>这一条命令就是将drivers&#x2F;media&#x2F;i2c&#x2F;ov5640.c编译成drivers&#x2F;media&#x2F;i2c&#x2F;ov5640.o。</p>
<h2 id="4-Makefile-modpost"><a href="#4-Makefile-modpost" class="headerlink" title="4. Makefile.modpost"></a><font size=3>4. Makefile.modpost</font></h2><h3 id="4-1-文件结构"><a href="#4-1-文件结构" class="headerlink" title="4.1 文件结构"></a><font size=3>4.1 文件结构</font></h3><p>最后我们来看<code>%.ko</code>目标的最后一条命令：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$(Q)</span>make -f <span class="variable">$(srctree)</span>/scripts/Makefile.modpost</span><br></pre></td></tr></table></figure>

<p>这里的srctree&#x3D;<code>.</code>，所以要分析的是这个文件：<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.modpost">Makefile.modpost - scripts&#x2F;Makefile.modpost</a>。先来看一下文件开头的注释：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Stage one of module building created the following:</span></span><br><span class="line"><span class="comment"># a) The individual .o files used for the module</span></span><br><span class="line"><span class="comment"># b) A &lt;module&gt;.o file which is the .o files above linked together</span></span><br><span class="line"><span class="comment"># c) A &lt;module&gt;.mod file in $(MODVERDIR)/, listing the name of the the preliminary &lt;module&gt;.o file, plus all .o files</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Stage 2 is handled by this file and does the following</span></span><br><span class="line"><span class="comment"># 1) Find all modules from the files listed in $(MODVERDIR)/</span></span><br><span class="line"><span class="comment"># 2) modpost is then used to</span></span><br><span class="line"><span class="comment"># 3)  create one &lt;module&gt;.mod.c file pr. module</span></span><br><span class="line"><span class="comment"># 4)  create one Module.symvers file with CRC for all exported symbols</span></span><br><span class="line"><span class="comment"># 5) compile all &lt;module&gt;.mod.c files</span></span><br><span class="line"><span class="comment"># 6) final link of the module to a &lt;module.ko&gt; file</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Step 3 is used to place certain information in the module&#x27;s ELF section, including information such as:</span></span><br><span class="line"><span class="comment">#   Version magic (see include/linux/vermagic.h for full details)</span></span><br><span class="line"><span class="comment">#     - Kernel release</span></span><br><span class="line"><span class="comment">#     - SMP is CONFIG_SMP</span></span><br><span class="line"><span class="comment">#     - PREEMPT is CONFIG_PREEMPT</span></span><br><span class="line"><span class="comment">#     - GCC Version</span></span><br><span class="line"><span class="comment">#   Module info</span></span><br><span class="line"><span class="comment">#     - Module version (MODULE_VERSION)</span></span><br><span class="line"><span class="comment">#     - Module alias&#x27;es (MODULE_ALIAS)</span></span><br><span class="line"><span class="comment">#     - Module license (MODULE_LICENSE)</span></span><br><span class="line"><span class="comment">#     - See include/linux/module.h for more details</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Step 4 is solely used to allow module versioning in external modules, where the CRC of each module is retrieved from the Module.symvers file.</span></span><br></pre></td></tr></table></figure>

<p>这里其实就是一个构建ko驱动文件的说明，主要分了4个阶段。我们打开文件就会发现，文件中有一些注释来告诉我们哪些是第一阶段，哪些是第二阶段。为什么要先看这个？因为我没找到默认目标，属于完全没看懂的样子，然后就发现这个文件中有不同阶段的注释，先来看一看吧。</p>
<h4 id="4-1-1-Step-1"><a href="#4-1-1-Step-1" class="headerlink" title="4.1.1 Step 1"></a><font size=3>4.1.1 <em>Step 1</em></font></h4><p><a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.modpost#L63">Makefile.modpost - scripts&#x2F;Makefile.modpost - <em>Step 1</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Step 1), find all modules listed in $(MODVERDIR)/</span></span><br><span class="line">MODLISTCMD := find <span class="variable">$(MODVERDIR)</span> -name &#x27;*.mod&#x27; | xargs -r grep -h &#x27;\.ko$$&#x27; | sort -u</span><br><span class="line">__modules := <span class="variable">$(<span class="built_in">shell</span> <span class="variable">$(MODLISTCMD)</span>)</span></span><br><span class="line">modules   := <span class="variable">$(<span class="built_in">patsubst</span> %.o,%.ko, $(<span class="built_in">wildcard</span> $(__modules:.ko=.o)</span>))</span><br><span class="line"></span><br><span class="line"><span class="comment"># Stop after building .o files if NOFINAL is set. Makes compile tests quicker</span></span><br><span class="line"><span class="section">_modpost: $(if <span class="variable">$(KBUILD_MODPOST_NOFINAL)</span>, $(modules:.ko:.o),<span class="variable">$(modules)</span>)</span></span><br></pre></td></tr></table></figure>

<h4 id="4-1-2-Step-2-3-4"><a href="#4-1-2-Step-2-3-4" class="headerlink" title="4.1.2 Step 2&#x2F;3&#x2F;4"></a><font size=3>4.1.2 <em>Step 2&#x2F;3&#x2F;4</em></font></h4><p><a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.modpost#L71">Makefile.modpost - scripts&#x2F;Makefile.modpost - <em>Step 2&#x2F;3&#x2F;4</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Step 2), invoke modpost</span></span><br><span class="line"><span class="comment">#  Includes step 3,4</span></span><br><span class="line">modpost = scripts/mod/modpost                    \</span><br><span class="line"> <span class="variable">$(<span class="built_in">if</span> <span class="variable">$(CONFIG_MODVERSIONS)</span>,-m)</span>                  \</span><br><span class="line"> <span class="variable">$(<span class="built_in">if</span> <span class="variable">$(CONFIG_MODULE_SRCVERSION_ALL)</span>,-a,)</span>       \</span><br><span class="line"> <span class="variable">$(<span class="built_in">if</span> <span class="variable">$(KBUILD_EXTMOD)</span>,-i,-o)</span> <span class="variable">$(kernelsymfile)</span>   \</span><br><span class="line"> <span class="variable">$(<span class="built_in">if</span> <span class="variable">$(KBUILD_EXTMOD)</span>,-I <span class="variable">$(modulesymfile)</span>)</span>      \</span><br><span class="line"> <span class="variable">$(<span class="built_in">if</span> <span class="variable">$(KBUILD_EXTMOD)</span>,$(<span class="built_in">addprefix</span> -e ,<span class="variable">$(KBUILD_EXTRA_SYMBOLS)</span>)</span>) \</span><br><span class="line"> <span class="variable">$(<span class="built_in">if</span> <span class="variable">$(KBUILD_EXTMOD)</span>,-o <span class="variable">$(modulesymfile)</span>)</span>      \</span><br><span class="line"> <span class="variable">$(<span class="built_in">if</span> <span class="variable">$(CONFIG_DEBUG_SECTION_MISMATCH)</span>,,-S)</span>      \</span><br><span class="line"> <span class="variable">$(<span class="built_in">if</span> <span class="variable">$(CONFIG_SECTION_MISMATCH_WARN_ONLY)</span>,,-E)</span>  \</span><br><span class="line"> <span class="variable">$(<span class="built_in">if</span> <span class="variable">$(KBUILD_EXTMOD)</span><span class="variable">$(KBUILD_MODPOST_WARN)</span>,-w)</span></span><br><span class="line"></span><br><span class="line">MODPOST_OPT=<span class="variable">$(<span class="built_in">subst</span> -i,-n,$(<span class="built_in">filter</span> -i,<span class="variable">$(MAKEFLAGS)</span>)</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># We can go over command line length here, so be careful.</span></span><br><span class="line">quiet_cmd_modpost = MODPOST <span class="variable">$(words $(<span class="built_in">filter</span>-out vmlinux FORCE, <span class="variable">$^</span>)</span>) modules</span><br><span class="line">      cmd_modpost = <span class="variable">$(MODLISTCMD)</span> | sed &#x27;s/\.ko$$/.o/&#x27; | <span class="variable">$(modpost)</span> <span class="variable">$(MODPOST_OPT)</span> -s -T -</span><br><span class="line"></span><br><span class="line">PHONY += __modpost</span><br><span class="line"><span class="section">__modpost: $(modules:.ko=.o) FORCE</span></span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> cmd,modpost)</span> <span class="variable">$(<span class="built_in">wildcard</span> vmlinux)</span></span><br><span class="line"></span><br><span class="line">quiet_cmd_kernel-mod = MODPOST <span class="variable">$@</span></span><br><span class="line">      cmd_kernel-mod = <span class="variable">$(modpost)</span> <span class="variable">$@</span></span><br><span class="line"></span><br><span class="line"><span class="section">vmlinux.o: FORCE</span></span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> cmd,kernel-mod)</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Declare generated files as targets for modpost</span></span><br><span class="line"><span class="section">$(modules:.ko=.mod.c): __modpost ;</span></span><br></pre></td></tr></table></figure>

<h4 id="4-1-3-Step-5"><a href="#4-1-3-Step-5" class="headerlink" title="4.1.3 Step 5"></a><font size=3>4.1.3 <em>Step 5</em></font></h4><p><a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.modpost#L104">Makefile.modpost - scripts&#x2F;Makefile.modpost - <em>Step 5</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Step 5), compile all *.mod.c files</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># modname is set to make c_flags define KBUILD_MODNAME</span></span><br><span class="line">modname = <span class="variable">$(<span class="built_in">notdir</span> $(@:.mod.o=)</span>)</span><br><span class="line"></span><br><span class="line">quiet_cmd_cc_o_c = CC      <span class="variable">$@</span></span><br><span class="line">      cmd_cc_o_c = <span class="variable">$(CC)</span> <span class="variable">$(c_flags)</span> <span class="variable">$(KBUILD_CFLAGS_MODULE)</span> <span class="variable">$(CFLAGS_MODULE)</span> \</span><br><span class="line">		   -c -o <span class="variable">$@</span> <span class="variable">$&lt;</span></span><br><span class="line"></span><br><span class="line"><span class="section">$(modules:.ko=.mod.o): %.mod.o: %.mod.c FORCE</span></span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> if_changed_dep,cc_o_c)</span></span><br><span class="line"></span><br><span class="line">targets += $(modules:.ko=.mod.o)</span><br><span class="line"></span><br><span class="line">ARCH_POSTLINK := <span class="variable">$(<span class="built_in">wildcard</span> <span class="variable">$(srctree)</span>/arch/<span class="variable">$(SRCARCH)</span>/Makefile.postlink)</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Step 6), final link of the modules with optional arch pass after final link</span></span><br><span class="line">quiet_cmd_ld_ko_o = LD [M]  <span class="variable">$@</span></span><br><span class="line">      cmd_ld_ko_o =                                                     \</span><br><span class="line">	<span class="variable">$(LD)</span> -r <span class="variable">$(KBUILD_LDFLAGS)</span>                                      \</span><br><span class="line">                 <span class="variable">$(KBUILD_LDFLAGS_MODULE)</span> <span class="variable">$(LDFLAGS_MODULE)</span>             \</span><br><span class="line">                 -o <span class="variable">$@</span> <span class="variable">$(<span class="built_in">filter</span>-out FORCE,<span class="variable">$^</span>)</span> ;                         \</span><br><span class="line">	<span class="variable">$(<span class="built_in">if</span> <span class="variable">$(ARCH_POSTLINK)</span>, <span class="variable">$(MAKE)</span> -f <span class="variable">$(ARCH_POSTLINK)</span> <span class="variable">$@</span>, true)</span></span><br><span class="line"></span><br><span class="line"><span class="variable">$(modules)</span>: %.ko :%.o %.mod.o FORCE</span><br><span class="line">	+<span class="variable">$(<span class="built_in">call</span> if_changed,ld_ko_o)</span></span><br><span class="line"></span><br><span class="line">targets += <span class="variable">$(modules)</span></span><br></pre></td></tr></table></figure>



<h4 id="4-1-4-所有出现的目标"><a href="#4-1-4-所有出现的目标" class="headerlink" title="4.1.4 所有出现的目标"></a><font size=3>4.1.4 所有出现的目标</font></h4><p>简化一下，看看所有出现的目标吧：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">PHONY := _modpost</span><br><span class="line"><span class="section">_modpost: __modpost</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Step 1), find all modules listed in $(MODVERDIR)/</span></span><br><span class="line"><span class="comment"># Stop after building .o files if NOFINAL is set. Makes compile tests quicker</span></span><br><span class="line"><span class="section">_modpost: $(if <span class="variable">$(KBUILD_MODPOST_NOFINAL)</span>, $(modules:.ko:.o),<span class="variable">$(modules)</span>)</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Step 2), invoke modpost</span></span><br><span class="line"><span class="comment">#  Includes step 3,4</span></span><br><span class="line">PHONY += __modpost</span><br><span class="line"><span class="section">__modpost: $(modules:.ko=.o) FORCE</span></span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> cmd,modpost)</span> <span class="variable">$(<span class="built_in">wildcard</span> vmlinux)</span></span><br><span class="line"></span><br><span class="line"><span class="section">vmlinux.o: FORCE</span></span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> cmd,kernel-mod)</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Declare generated files as targets for modpost</span></span><br><span class="line"><span class="section">$(modules:.ko=.mod.c): __modpost ;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Step 5), compile all *.mod.c files</span></span><br><span class="line"><span class="section">$(modules:.ko=.mod.o): %.mod.o: %.mod.c FORCE</span></span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> if_changed_dep,cc_o_c)</span></span><br><span class="line">	</span><br><span class="line"><span class="variable">$(modules)</span>: %.ko :%.o %.mod.o FORCE</span><br><span class="line">	+<span class="variable">$(<span class="built_in">call</span> if_changed,ld_ko_o)</span></span><br></pre></td></tr></table></figure>

<p>可以看到 _modpost是出现的第一个规则，他应该是默认规则，这个规则第一次出现的时候依赖于__modpost目标，然后往后就会发现，第7行又出现了它的新的依赖，那么怎么执行的？我们来试一下一个目标先后出现不同的规则的时候怎么运行的：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">PHONY += test</span><br><span class="line"><span class="section">test: test2</span></span><br><span class="line"></span><br><span class="line"><span class="section">test: test1</span></span><br><span class="line"></span><br><span class="line"><span class="section">test1:</span></span><br><span class="line">	@echo <span class="string">&quot;test1&quot;</span></span><br><span class="line">	</span><br><span class="line"><span class="section">test2:</span></span><br><span class="line">	@echo <span class="string">&quot;test2&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="meta"><span class="keyword">.PHONY</span>: $(PHONY)</span></span><br></pre></td></tr></table></figure>

<p>我们执行make，会有如下打印信息：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">test1</span><br><span class="line">test2</span><br></pre></td></tr></table></figure>

<p>实践证明，只要是目标依赖的目标中的规则都会执行，并且先出现的先执行。所以这里我们大概就可以知道怎么去跟这部分的代码了。</p>
<h3 id="4-2-modpost目标"><a href="#4-2-modpost目标" class="headerlink" title="4.2 _modpost目标"></a><font size=3>4.2 _modpost目标</font></h3><p>默认目标是哪个？一般来说makefile的第一个目标就是默认目标，刚才大分析文件结构的时候大概已经清楚默认目标了，我们打开<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.modpost#L41">Makefile.modpost - scripts&#x2F;Makefile.modpost</a>，看到的第一个目标就是：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">PHONY := _modpost</span><br><span class="line"><span class="section">_modpost: __modpost</span></span><br></pre></td></tr></table></figure>

<p>可以看到_modpost又依赖于__modpost，这个时候就会先去完成__modpost目标中的规则。</p>
<h3 id="4-3-modpost目标"><a href="#4-3-modpost目标" class="headerlink" title="4.3 __modpost目标"></a><font size=3>4.3 __modpost目标</font></h3><p>接下来先来看这个__modpost目标，它定义在 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.modpost#L91">Makefile.modpost - scripts&#x2F;Makefile.modpost - <em>__modpost目标</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">PHONY += __modpost</span><br><span class="line"><span class="section">__modpost: $(modules:.ko=.o) FORCE</span></span><br><span class="line">	<span class="variable">$(<span class="built_in">call</span> cmd,modpost)</span> <span class="variable">$(<span class="built_in">wildcard</span> vmlinux)</span></span><br></pre></td></tr></table></figure>

<h4 id="4-3-1-call-cmd-modpost"><a href="#4-3-1-call-cmd-modpost" class="headerlink" title="4.3.1 $(call cmd,modpost)"></a><font size=3>4.3.1 <code>$(call cmd,modpost)</code></font></h4><p>先来看这个<code>$(call cmd,modpost)</code>命令，cmd函数定义在：<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Kbuild.include#L224">Kbuild.include - scripts&#x2F;Kbuild.include - <em>cmd</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># echo command.</span></span><br><span class="line"><span class="comment"># Short version is used, if $(quiet) equals `quiet_&#x27;, otherwise full one.</span></span><br><span class="line">echo-cmd = <span class="variable">$(<span class="built_in">if</span> $(<span class="variable">$(quiet)</span>cmd_$(1)</span>),\</span><br><span class="line">	echo &#x27;  <span class="variable">$(<span class="built_in">call</span> escsq,$(<span class="variable">$(quiet)</span>cmd_$(1)</span>))$(echo-why)&#x27;;)</span><br><span class="line"></span><br><span class="line"><span class="comment"># printing commands</span></span><br><span class="line">cmd = @$(echo-cmd) $(cmd_$(1))</span><br></pre></td></tr></table></figure>

<p>直接看<code>$(cmd_$(1))</code>，前面cmd函数调用的时候传入的参数是modpost，所以<code>$(1)</code>&#x3D;modpost，这里就是<code>$(cmd_modpost)</code>，定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.modpost#L88">Makefile.modpost - scripts&#x2F;Makefile.modpost - <em>cmd_modpost</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># We can go over command line length here, so be careful.</span></span><br><span class="line">quiet_cmd_modpost = MODPOST <span class="variable">$(words $(<span class="built_in">filter</span>-out vmlinux FORCE, <span class="variable">$^</span>)</span>) modules</span><br><span class="line">      cmd_modpost = <span class="variable">$(MODLISTCMD)</span> | sed &#x27;s/\.ko$$/.o/&#x27; | <span class="variable">$(modpost)</span> <span class="variable">$(MODPOST_OPT)</span> -s -T -</span><br></pre></td></tr></table></figure>

<p>MODLISTCMD定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.modpost#L64">Makefile.modpost - scripts&#x2F;Makefile.modpost - <em>MODLISTCMD</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">MODLISTCMD := find <span class="variable">$(MODVERDIR)</span> -name &#x27;*.mod&#x27; | xargs -r grep -h &#x27;\.ko$$&#x27; | sort -u</span><br></pre></td></tr></table></figure>

<p>MODPOST_OPT定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.modpost#L84">Makefile.modpost - scripts&#x2F;Makefile.modpost - <em>MODPOST_OPT</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">MODPOST_OPT=<span class="variable">$(<span class="built_in">subst</span> -i,-n,$(<span class="built_in">filter</span> -i,<span class="variable">$(MAKEFLAGS)</span>)</span>)</span><br></pre></td></tr></table></figure>

<p>modpost定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.modpost#L73">Makefile.modpost - scripts&#x2F;Makefile.modpost - <em>modpost</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">modpost = scripts/mod/modpost                    \</span><br><span class="line"> <span class="variable">$(<span class="built_in">if</span> <span class="variable">$(CONFIG_MODVERSIONS)</span>,-m)</span>                  \</span><br><span class="line"> <span class="variable">$(<span class="built_in">if</span> <span class="variable">$(CONFIG_MODULE_SRCVERSION_ALL)</span>,-a,)</span>       \</span><br><span class="line"> <span class="variable">$(<span class="built_in">if</span> <span class="variable">$(KBUILD_EXTMOD)</span>,-i,-o)</span> <span class="variable">$(kernelsymfile)</span>   \</span><br><span class="line"> <span class="variable">$(<span class="built_in">if</span> <span class="variable">$(KBUILD_EXTMOD)</span>,-I <span class="variable">$(modulesymfile)</span>)</span>      \</span><br><span class="line"> <span class="variable">$(<span class="built_in">if</span> <span class="variable">$(KBUILD_EXTMOD)</span>,$(<span class="built_in">addprefix</span> -e ,<span class="variable">$(KBUILD_EXTRA_SYMBOLS)</span>)</span>) \</span><br><span class="line"> <span class="variable">$(<span class="built_in">if</span> <span class="variable">$(KBUILD_EXTMOD)</span>,-o <span class="variable">$(modulesymfile)</span>)</span>      \</span><br><span class="line"> <span class="variable">$(<span class="built_in">if</span> <span class="variable">$(CONFIG_DEBUG_SECTION_MISMATCH)</span>,,-S)</span>      \</span><br><span class="line"> <span class="variable">$(<span class="built_in">if</span> <span class="variable">$(CONFIG_SECTION_MISMATCH_WARN_ONLY)</span>,,-E)</span>  \</span><br><span class="line"> <span class="variable">$(<span class="built_in">if</span> <span class="variable">$(KBUILD_EXTMOD)</span><span class="variable">$(KBUILD_MODPOST_WARN)</span>,-w)</span></span><br></pre></td></tr></table></figure>

<p>这里涉及的变量较多，我们直接看打印信息吧，因为它调用的是cmd函数，所以是带有命令回显的：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">find .tmp_versions -name &#x27;*.mod&#x27; | xargs -r grep -h &#x27;\.ko$&#x27; | sort -u | sed &#x27;s/\.ko$/.o/&#x27; | scripts/mod/modpost -m -a -o ./Module.symvers    -S    -s -T -</span><br></pre></td></tr></table></figure>

<p>这行打印新奇其实就是在执行<code>$(call cmd,modpost)</code>。这里不深究了先到此为止。</p>
<h4 id="4-3-2-wildcard-vmlinux"><a href="#4-3-2-wildcard-vmlinux" class="headerlink" title="4.3.2 $(wildcard vmlinux)"></a><font size=3>4.3.2 <code>$(wildcard vmlinux)</code></font></h4><p>这个 wildcard 函数用于查找匹配指定模式的文件，并返回这些文件的列表。这个函数在处理文件路径和文件名时非常有用，特别是在需要动态生成文件列表的情况下。一般用法如下：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$(<span class="built_in">wildcard</span> 指定文件类型)</span></span><br></pre></td></tr></table></figure>

<p>所以这里其实是在匹配当前路径下的vmlinux文件。显然这里为空。</p>
<h4 id="4-3-3-modules-ko-o"><a href="#4-3-3-modules-ko-o" class="headerlink" title="4.3.3 $(modules:.ko=.o)"></a><font size=3>4.3.3 <code>$(modules:.ko=.o)</code></font></h4><p>前面__modpost目标还依赖于<code>$(modules:.ko=.o)</code>，我们来看一下这是个什么。再来看一下这个依赖项，这个内部其实是makefile中的字符串替换语法，就是把modules中所有成员的.ko替换成.o。modules变量定义在 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.modpost#L66">Makefile.modpost - scripts&#x2F;Makefile.modpost - <em>modules</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">modules   := <span class="variable">$(<span class="built_in">patsubst</span> %.o,%.ko, $(<span class="built_in">wildcard</span> $(__modules:.ko=.o)</span>))</span><br></pre></td></tr></table></figure>

<p>这里直接在这个位置加个打印信息吧：<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.modpost#L92">Makefile.modpost - scripts&#x2F;Makefile.modpost</a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">PHONY += __modpost</span><br><span class="line"><span class="section">__modpost: $(modules:.ko=.o) FORCE</span></span><br><span class="line">	<span class="variable">$(<span class="built_in">warning</span> &quot;info modules=<span class="variable">$(modules)</span> (modules:.ko=.o)</span>=$(modules:.ko=.o)<span class="string">&quot;)</span></span><br><span class="line"><span class="string">	$(call cmd,modpost) $(wildcard vmlinux)</span></span><br></pre></td></tr></table></figure>

<p>然后执行以下命令：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">make V=0 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean</span><br><span class="line">make V=0 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_v6_v7_defconfig</span><br><span class="line">make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- drivers/media/i2c/ov5640.ko -j16</span><br></pre></td></tr></table></figure>

<p>可以看到如下打印信息：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">scripts/Makefile.modpost:94: &quot;info modules=drivers/media/i2c/ov5640.ko (modules:.ko=.o)=drivers/media/i2c/ov5640.o&quot;</span></span><br></pre></td></tr></table></figure>

<p>这里其实就是依赖于drivers&#x2F;media&#x2F;i2c&#x2F;ov5640.o。这个文件在前面已经生成了的。</p>
<h4 id="4-3-4-总结"><a href="#4-3-4-总结" class="headerlink" title="4.3.4 总结"></a><font size=3>4.3.4 总结</font></h4><p>所以这个__modpost目标中的规则是在执行这条命令：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">find .tmp_versions -name &#x27;*.mod&#x27; | xargs -r grep -h &#x27;\.ko$&#x27; | sort -u | sed &#x27;s/\.ko$/.o/&#x27; | scripts/mod/modpost -m -a -o ./Module.symvers    -S    -s -T -</span><br></pre></td></tr></table></figure>

<p>这里也就不再深究了。</p>
<h3 id="4-4-modpost目标"><a href="#4-4-modpost目标" class="headerlink" title="4.4 _modpost目标"></a><font size=3>4.4 _modpost目标</font></h3><p>上面已经分析完了，接下来再来看下一个_modpost目标，定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.modpost#L69">Makefile.modpost - scripts&#x2F;Makefile.modpost - <em>_modpost</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Stop after building .o files if NOFINAL is set. Makes compile tests quicker</span></span><br><span class="line"><span class="section">_modpost: $(if <span class="variable">$(KBUILD_MODPOST_NOFINAL)</span>, $(modules:.ko:.o),<span class="variable">$(modules)</span>)</span></span><br></pre></td></tr></table></figure>

<p>直接在这里加打印信息吧，我是没找到在哪定义：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">_modpost: $(if <span class="variable">$(KBUILD_MODPOST_NOFINAL)</span>, $(modules:.ko:.o),<span class="variable">$(modules)</span>)</span></span><br><span class="line">	<span class="variable">$(<span class="built_in">warning</span> KBUILD_MODPOST_NOFINAL=<span class="variable">$(KBUILD_MODPOST_NOFINAL)</span> (modules:.ko:.o)</span>=$(modules:.ko:.o) modules=<span class="variable">$(modules)</span>)</span><br></pre></td></tr></table></figure>

<p>查看打印信息如下：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">scripts/Makefile.modpost:70: KBUILD_MODPOST_NOFINAL= (modules:.ko:.o)= modules=drivers/media/i2c/ov5640.ko</span></span><br></pre></td></tr></table></figure>

<p>所以其实上面展开就是：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Stop after building .o files if NOFINAL is set. Makes compile tests quicker</span></span><br><span class="line"><span class="section">_modpost: drivers/media/i2c/ov5640.ko</span></span><br></pre></td></tr></table></figure>

<p>就这样，又产生了一个要追的目标<code>$(modules)</code>。</p>
<h3 id="4-5-modules-目标"><a href="#4-5-modules-目标" class="headerlink" title="4.5 $(modules)目标"></a><font size=3>4.5 <code>$(modules)</code>目标</font></h3><p>接下来我们来看<code>$(modules)</code>目标，它定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.modpost#L128">Makefile.modpost - scripts&#x2F;Makefile.modpost - <em>modules</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$(modules)</span>: %.ko :%.o %.mod.o FORCE</span><br><span class="line">	+<span class="variable">$(<span class="built_in">call</span> if_changed,ld_ko_o)</span></span><br></pre></td></tr></table></figure>

<h4 id="4-5-1-if-changed函数"><a href="#4-5-1-if-changed函数" class="headerlink" title="4.5.1 if_changed函数"></a><font size=3>4.5.1 if_changed函数</font></h4><p>if_changed函数定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Kbuild.include#L259">Kbuild.include - scripts&#x2F;Kbuild.include - <em>if_changed</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Execute command if command has changed or prerequisite(s) are updated.</span></span><br><span class="line">if_changed = <span class="variable">$(<span class="built_in">if</span> $(<span class="built_in">strip</span> $(any-prereq)</span> $(arg-check)),                       \</span><br><span class="line">	@set -e;                                                             \</span><br><span class="line">	$(echo-cmd) $(cmd_$(1));                                             \</span><br><span class="line">	printf &#x27;%s\n&#x27; &#x27;cmd_<span class="variable">$@</span> := $(make-cmd)&#x27; &gt; $(dot-target).cmd, @:)</span><br></pre></td></tr></table></figure>

<p>由于我么要生成ko文件，这里<code>$(any-prereq)</code>和 <code>$(arg-check)</code>至少有一个不会为空，所以这里简化为：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Execute command if command has changed or prerequisite(s) are updated.</span></span><br><span class="line">if_changed =                                                             \</span><br><span class="line">	@set -e;                                                             \</span><br><span class="line">	$(echo-cmd) $(cmd_$(1));                                             \</span><br><span class="line">	printf &#x27;%s\n&#x27; &#x27;cmd_<span class="variable">$@</span> := $(make-cmd)&#x27; &gt; $(dot-target).cmd</span><br></pre></td></tr></table></figure>

<p>前面其实分析过<code>$(echo-cmd) $(cmd_$(1))</code>这句在干什么，<code>$(echo-cmd)</code>负责命令回显，<code>$(cmd_$(1))</code>负责命令执行。所以这里我们直接看这个<code>$(cmd_$(1))</code>即可。这里就是<code>$(cmd_ld_ko_o)</code>。</p>
<h4 id="4-5-2-cmd-ld-ko-o"><a href="#4-5-2-cmd-ld-ko-o" class="headerlink" title="4.5.2 cmd_ld_ko_o"></a><font size=3>4.5.2 <code>cmd_ld_ko_o</code></font></h4><p>cmd_ld_ko_o定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/scripts/Makefile.modpost#L122">Makefile.modpost - scripts&#x2F;Makefile.modpost - <em>cmd_ld_ko_o</em></a>：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Step 6), final link of the modules with optional arch pass after final link</span></span><br><span class="line">quiet_cmd_ld_ko_o = LD [M]  <span class="variable">$@</span></span><br><span class="line">      cmd_ld_ko_o =                                                     \</span><br><span class="line">	<span class="variable">$(LD)</span> -r <span class="variable">$(KBUILD_LDFLAGS)</span>                                      \</span><br><span class="line">                 <span class="variable">$(KBUILD_LDFLAGS_MODULE)</span> <span class="variable">$(LDFLAGS_MODULE)</span>             \</span><br><span class="line">                 -o <span class="variable">$@</span> <span class="variable">$(<span class="built_in">filter</span>-out FORCE,<span class="variable">$^</span>)</span> ;                         \</span><br><span class="line">	<span class="variable">$(<span class="built_in">if</span> <span class="variable">$(ARCH_POSTLINK)</span>, <span class="variable">$(MAKE)</span> -f <span class="variable">$(ARCH_POSTLINK)</span> <span class="variable">$@</span>, true)</span></span><br></pre></td></tr></table></figure>

<p>那这句是什么？其实吧前面分析过的<code>$(echo-cmd)</code>可以回显命令的，显示的就是后面的<code>$(cmd_$(1))</code>在这里就是cmd_ld_ko_o，为了方便区分，我们在这里加一条打印：</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">     cmd_ld_ko_o =                                                     \</span><br><span class="line">     echo <span class="string">&quot;cmd_ld_ko_o info &gt;&gt;&gt;&quot;</span>;\</span><br><span class="line"><span class="variable">$(LD)</span> -r <span class="variable">$(KBUILD_LDFLAGS)</span>                                      \</span><br><span class="line">                <span class="variable">$(KBUILD_LDFLAGS_MODULE)</span> <span class="variable">$(LDFLAGS_MODULE)</span>             \</span><br><span class="line">                -o <span class="variable">$@</span> <span class="variable">$(<span class="built_in">filter</span>-out FORCE,<span class="variable">$^</span>)</span> ;                         \</span><br><span class="line"><span class="variable">$(<span class="built_in">if</span> <span class="variable">$(ARCH_POSTLINK)</span>, <span class="variable">$(MAKE)</span> -f <span class="variable">$(ARCH_POSTLINK)</span> <span class="variable">$@</span>, true)</span></span><br></pre></td></tr></table></figure>

<p>这里不能用<code>$(warning)</code>来打印，会报错。然后我们执行：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">make V=0 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean</span><br><span class="line">make V=0 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_v6_v7_defconfig</span><br><span class="line">make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- drivers/media/i2c/ov5640.ko -j16</span><br></pre></td></tr></table></figure>

<p>会看到如下打印信息：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">  echo &quot;cmd_ld_ko_o info &gt;&gt;&gt;&quot;; arm-linux-gnueabihf-ld -r  -EL -T ./scripts/module-common.lds -T ./arch/arm/kernel/module.lds  --build-id  -o drivers/media/i2c/ov5640.ko drivers/media/i2c/ov5640.o drivers/media/i2c/ov5640.mod.o ;  true</span><br><span class="line">cmd_ld_ko_o info &gt;&gt;&gt;</span><br></pre></td></tr></table></figure>

<p>所以其实下面这条就是cmd_ld_ko_o的命令回显啦：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">echo &quot;cmd_ld_ko_o info &gt;&gt;&gt;&quot;; arm-linux-gnueabihf-ld -r  -EL -T ./scripts/module-common.lds -T ./arch/arm/kernel/module.lds  --build-id  -o drivers/media/i2c/ov5640.ko drivers/media/i2c/ov5640.o drivers/media/i2c/ov5640.mod.o ;  true</span><br></pre></td></tr></table></figure>

<p>可以看到这里其实就是arm-linux-gnueabihf-ld将相关的.o文件链接成drivers&#x2F;media&#x2F;i2c&#x2F;ov5640.ko的命令，到此为止，我们就生成了最终的 drivers&#x2F;media&#x2F;i2c&#x2F;ov5640.ko：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV05-%E7%B3%BB%E7%BB%9F%E9%95%9C%E5%83%8F/LV05-03-Kernel-03-02-make-single-module/img/image-20241129001133528.png" alt="image-20241129001133528" />


    </div>

    
    
    

    <footer class="post-footer">




    <div>
        
            <div style="text-align:center;color: #ccc;font-size:14px;">
            ----------本文结束
            <i class="fas fa-fan fa-spin" style="color: #FF1493; font-size: 1rem"></i>
            感谢您的阅读----------
            </div>
        
    </div>





  
  <div class="my_post_copyright"> 
    <p><span>文章标题:</span><a href="/post/5d81934f.html">LV05-03-Kernel-03-02-make-single-module</a></p>
    <p><span>文章作者:</span><a href="/" title="欢迎访问 《苏木》 的学习笔记">苏木</a></p>
    <p><span>发布时间:</span>2024年11月29日 - 10:27</p>
    <p><span>最后更新:</span>2025年06月14日 - 00:25</p>
    <p><span>原始链接:</span><a href="/post/5d81934f.html" title="LV05-03-Kernel-03-02-make-single-module">https://sumumm.github.io/post/5d81934f.html</a></p>
    <p><span>许可协议:</span><i class="fab fa-creative-commons"></i> <a rel="license" href= "https://creativecommons.org/licenses/by-nc-nd/4.0/" target="_blank" title="Attribution-NonCommercial-NoDerivatives 4.0 International (CC BY-NC-ND 4.0)">署名-非商业性使用-禁止演绎 4.0 国际</a> 转载请保留原文链接及作者。</p>  
  </div>
  


          <div class="post-tags">
              <a href="/tags/LV05-%E7%B3%BB%E7%BB%9F%E9%95%9C%E5%83%8F/" rel="tag"><i class="fa fa-tag"></i> LV05-系统镜像</a>
          </div>

        

          <div class="post-nav">
            <div class="post-nav-item">
                <a href="/post/c9182535.html" rel="prev" title="LV05-04-根文件系统-01-根文件系统基础">
                  <i class="fa fa-angle-left"></i> LV05-04-根文件系统-01-根文件系统基础
                </a>
            </div>
            <div class="post-nav-item">
                <a href="/post/2aa70834.html" rel="next" title="LV05-03-Kernel-03-01-顶层Makefile基础解析">
                  LV05-03-Kernel-03-01-顶层Makefile基础解析 <i class="fa fa-angle-right"></i>
                </a>
            </div>
          </div>
    </footer>
  </article>
</div>






</div>
  </main>

  <footer class="footer">
    <div class="footer-inner">

  <div class="copyright">
    &copy; 2017 – 
    <span itemprop="copyrightYear">2025</span>
    <span class="with-love">
      <i class="fa fa-heart"></i>
    </span>
    <span class="author" itemprop="copyrightHolder">苏木</span>
  </div>
<div class="wordcount">
  <span class="post-meta-item">
    <span class="post-meta-item-icon">
      <i class="fa fa-chart-line"></i>
    </span>
      <span>站点总字数：</span>
    <span title="站点总字数">3.7m</span>
  </span>
  <span class="post-meta-item">
    <span class="post-meta-item-icon">
      <i class="fa fa-coffee"></i>
    </span>
      <span>站点阅读时长 &asymp;</span>
    <span title="站点阅读时长">225:26</span>
  </span>
</div>




    <span id="sitetime"></span>
    <script defer language=javascript>
        function siteTime()
        {
            window.setTimeout("siteTime()", 1000);
            var seconds = 1000;
            var minutes = seconds * 60;
            var hours = minutes * 60;
            var days = hours * 24;
            var years = days * 365;
            var today = new Date();
            var todayYear = today.getFullYear();
            var todayMonth = today.getMonth()+1;
            var todayDate = today.getDate();
            var todayHour = today.getHours();
            var todayMinute = today.getMinutes();
            var todaySecond = today.getSeconds();
            /*==================================================
            Date.UTC() -- 返回date对象距世界标准时间(UTC)1970年1月1日午夜之间的毫秒数(时间戳)
            year        - 作为date对象的年份，为4位年份值
            month       - 0-11之间的整数，做为date对象的月份
            day         - 1-31之间的整数，做为date对象的天数
            hours       - 0(午夜24点)-23之间的整数，做为date对象的小时数
            minutes     - 0-59之间的整数，做为date对象的分钟数
            seconds     - 0-59之间的整数，做为date对象的秒数
            microseconds - 0-999之间的整数，做为date对象的毫秒数
            ==================================================*/
            var t1 = Date.UTC(2017, 
                              5, 
                              19, 
                              0, 
                              0, 
                              0); //北京时间
            var t2 = Date.UTC(todayYear,todayMonth,todayDate,todayHour,todayMinute,todaySecond);
            var diff = t2-t1;
            var diffYears = Math.floor(diff/years);
            var diffDays = Math.floor((diff/days)-diffYears*365);
            var diffHours = Math.floor((diff-(diffYears*365+diffDays)*days)/hours);
            var diffMinutes = Math.floor((diff-(diffYears*365+diffDays)*days-diffHours*hours)/minutes);
            var diffSeconds = Math.floor((diff-(diffYears*365+diffDays)*days-diffHours*hours-diffMinutes*minutes)/seconds);
            document.getElementById("sitetime").innerHTML="已在这里 "+diffYears+" 年 "+diffDays+" 天 "+diffHours+" 小时 "+diffMinutes+" 分钟 "+diffSeconds+" 秒";
        }
        siteTime();
    </script>



    </div>
  </footer>

  
  <div class="back-to-top" role="button" aria-label="返回顶部">
    <i class="fa fa-arrow-up fa-lg"></i>
    <span>0%</span>
  </div>
  <div class="reading-progress-bar"></div>

<noscript>
  <div class="noscript-warning">Theme NexT works best with JavaScript enabled</div>
</noscript>


  
  <script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js" integrity="sha256-XL2inqUJaslATFnHdJOi9GfQ60on8Wx1C2H8DYiN1xY=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/next-theme-pjax/0.6.0/pjax.min.js" integrity="sha256-vxLn1tSKWD4dqbMRyv940UYw4sXgMtYcK6reefzZrao=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/fancyapps-ui/5.0.28/fancybox/fancybox.umd.js" integrity="sha256-ytMJGN3toR+a84u7g7NuHm91VIR06Q41kMWDr2pq7Zo=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/lozad.js/1.16.0/lozad.min.js" integrity="sha256-mOFREFhqmHeQbXpK2lp4nA3qooVgACfh88fpJftLBbc=" crossorigin="anonymous"></script>
<script src="/js/comments.js"></script><script src="/js/utils.js"></script><script src="/js/motion.js"></script><script src="/js/next-boot.js"></script><script src="/js/pjax.js"></script>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/hexo-generator-searchdb/1.4.1/search.js" integrity="sha256-1kfA5uHPf65M5cphT2dvymhkuyHPQp5A53EGZOnOLmc=" crossorigin="anonymous"></script>
<script src="/js/third-party/search/local-search.js"></script>




  <script src="/js/third-party/fancybox.js"></script>

  <script src="/js/third-party/pace.js"></script>


  




  

  <script class="next-config" data-name="enableMath" type="application/json">true</script><script class="next-config" data-name="mathjax" type="application/json">{"enable":true,"tags":"none","js":{"url":"https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.2/es5/tex-mml-chtml.js","integrity":"sha256-MASABpB4tYktI2Oitl4t+78w/lyA+D7b/s9GEP0JOGI="}}</script>
<script src="/js/third-party/math/mathjax.js"></script>


 
        <div id="click-show-text"
            data-mobile = false
            data-text = 富强,民主,文明,和谐,自由,平等,公正,法制,爱国,敬业,诚信,友善
            data-fontsize = 15px
            data-random= false>
        </div>
       

      
        <script async src=https://cdn.jsdelivr.net/npm/hexo-next-mouse-effect@latest/click/showText.js></script>
      

      
    




    <script async src="/js/fancybox_param.js"></script>





<!-- APlayer本体 -->



</body>
</html>
